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?