Načítání modelu s NotORM, DI a inject

Od verze Nette 2.0.5 můžeme načítat modely pomocí Dependency Injection containeru (v konfiguračním souboru) a v presenteru pak využit autowire metodu inject. Výhodou řešení přes DI container je přehlednost a čistota zápisu.

Návod využítá Nette 2.0.5 a NotORM. Hledáte jak napojit dibi či Nette Database?

Konfigurujeme prostředí

config.neon

Nejprve si v konfiguračním souboru config.neon nastavíme potřebné parametry a registrujeme službu database. Pak můžeme přidávat jednotlivé modely.

parameters:
	# parametry pro připojení k databázi
	database:
		driver: mysql
		host: local
		username: root
		password:
		dbname: database

nette:
	# nutné pro aktivaci debugbaru
	database:
		default:
			dsn: "%database.driver%:host=%database.host%;dbname=%database.dbname%"
			user: %database.username%
			password: %database.password%

services:
	dbcache: NotORM_Cache_Include("%tempDir%/notorm.cache")
	database: NotORM(@\PDO, null, @dbcache)

	# přidáme jednotlivé modely
	userModel: Models\User
	articleModel: Models\Article

Modely

Abychom nemuseli v každém našem modelu opakovat stejný kód, vytvoříme si abstraktního předka. Ten nám definuje obecené metody a přístup k databázi.

BaseModel.php


namespace Models;

use Nette;
use NotORM;

abstract class Base
{
	/** @var NotORM */
	protected $db;

	/** @var string */
	private $tableName;


	/**
	 * @param NotORM
	 */
	public function __construct(NotORM $notorm)
	{
		$this->db = $notorm;
		$this->tableName = $this->tableNameByClass(get_class($this));
	}


	/**
	 * Určí tabulku dle názvu třídy
	 * @param string
	 * @return string
	 * @result: Pages => pages, ArticleTag => article_tag
	 */
	private function tableNameByClass($className)
	{
		$tableName = explode("\\", $className);
		$tableName = lcfirst(array_pop($tableName));

		$replace = []; // A => _a
		foreach (range("A", "Z") as $letter) {
			$replace[$letter] = "_" . strtolower($letter);
		}

		return strtr($tableName, $replace);
	}


	// přidáme vlastní metody: insert, update, delete, count,
	// fetchSingle, fetchPairs atd.

}

Vlastní model

Dědí všechny metody z Models\Base – ty můžeme ihned používat a dopsat si vlastní metody na míru.

namespace Models;

class User extends Base
{
	/**
	 * Return user by name
	 * @param string
	 */
	public function getByName($name)
	{
		return $this->db->user("name", $name)->fetch();
	}
}

Injectujeme

Nyní máme modely registrované jako služby. Abychom se vyhnuli použití $this->context, musíme je do presenterů injectovat.

Abychom se neupsali, můžeme v BasePresenter načíst ty modely, které budeme používat ve většině dalších presenterů.

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	/** @var Models\User */
	protected $userModel;


 	/**
   	 * Inject all models that are expected to be used in most of BasePresenter's ancestors
   	 * @param Models\User
	 */
	public function injectBaseModels(Models\User $userModel)
	{
		$this->userModel = $userModel;
	}

}

Používáme

class ArticlePresenter extends BasePresenter
{
	/** @var Models\Article */
	private $articleModel;


 	/**
   	 * @param Models\Article
	 */
	public function injectModels(Models\Article $articleModel)
	{
		$this->articleModel = $articleModel;
	}


	/**
	 * @param int
	 */
	public function actionDetail($id)
	{
		$this->template->article = $article = $this->articleModel->fetch($id);
		$this->template->articleAuthor = $this->userModel->fetch($article["user_id"]);
	}

}

Jednoduché, že?