Komponenta a její správné napojení na model
- tatyalien
- Člen | 239
Dobrý den,
udělal jsem si jednoduchou komponentu boxAkce, která má na starosti pouze,
že se vypíšou akce z databáze. Data do komponenty nalévám v presenteru
(profiltruji si databázi a vypíšu jen ty akce, které chci). Nikde, ale
nemám nadefinované, co komponenta potřebuje ke svému „životu“. Jaký je
správný postup? Sice si mohu dát do komentáře u komponenty, něco jako,
pro chod komponenty je nutné dodat \Nette\Database\Table\Selection, kde jsou
hodnoty: nazev, obsah. Ale tento postup se mi nějak nezamlouvá…
Též bych se chtěl dopracovat k tomu, abych místo:
{control boxAkce}
mohl zadat:
{control boxAkce, 8}
kde by číslo zobrazilo, kolik se zobrazí maximálně záznamů, jak tohoto docílit jednoduše? (s tím, že pokud se nezadá hodnota, vypíše to například max 10 záznamů.
Zkoušel jsem to pomocí:
class HomepagePresenter extends BasePresenter
{
private $akce;
public function actionDefault()
{
$this->akce = $this->model->getAkce()->where('zobrazit', 1)->where("od <= ?",
Date("Y-m-d"))->where('do >= ? OR do IS NULL', Date("Y-m-d"))->order('od, id');
}
protected function createComponentBoxAkce($limit=10)
{
// zde si ale nedokážu nastavit limit ze šablony
$akce = $this->akce->limit($limit);
return new BoxAkce($akce);
}
}
komponenta:
<?php
use Nette\Application\UI;
use Nette\Database\Table\Selection;
class BoxAkce extends UI\Control
{
/** @var \Nette\Database\Table\Selection */
private $akce;
public function __construct(Selection $akce)
{
parent::__construct(); # vždy je potřeba volat rodičovský konstruktor
$this->akce = $akce;
}
public function render()
{
$this->template->setFile(__DIR__ . '/BoxAkce.latte');
$this->template->akce = $this->akce;
$this->template->render();
}
}
- Ot@s
- Backer | 476
Parametr u komponenty …
{control boxAkce, 8}
… se přenáši jako parametr do render() komponenty. Pokud toho využiješ, donutí tě to upravit výše uvedený kód tak, aby byl více košer.
public function render($limit=10)
{
$this->template->setFile(__DIR__ . '/BoxAkce.latte');
$this->template->akce = $this->presenter->model->getAkce()->where('zobrazit', 1)->where("od <= ?", Date("Y-m-d"))->where('do >= ? OR do IS NULL', Date("Y-m-d"))->order('od, id')->limit($limit);
$this->template->render();
}
V HomepagePresenter pak stačí uvést:
protected function createComponentBoxAkce()
{
return new BoxAkce;
}
- tatyalien
- Člen | 239
Tak jsem to musel jen trochu upravit, na:
Komponenta:
<?php
use Nette\Application\UI;
use Nette\Database\Table\Selection;
class BoxAkce extends UI\Control
{
/** @var \ShopModel */
private $model;
public function __construct(\ShopModel $model)
{
parent::__construct(); # vždy je potřeba volat rodičovský konstruktor
$this->model = $model;
}
public function render($limit=10)
{
$this->template->setFile(__DIR__ . '/BoxAkce.latte');
$this->template->akce = $this->model->getAkce()->where('zobrazit', 1)->where("od <= ?", Date("Y-m-d"))->where('do >= ? OR do IS NULL', Date("Y-m-d"))->order('od, id')->limit($limit);
$this->template->render();
}
}
Presenter:
protected function createComponentBoxAkce()
{
return new BoxAkce($this->model);
}
Podle tvého kódu mě totiž házelo laděnku: Cannot read an undeclared property HomepagePresenter::$model, i když mám:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
/**
* * @var Model */
protected $model;
public function startup()
{
parent::startup();
$this->model = $this->getService('model');
}
a v homepage jsem zkusil i:
public function startup()
{
parent::startup();
}
Takto ale mám nyní přesunutou veškerou logiku do komponenty, s tím, že ví co přesně potřebuje (jaké hodnoty z databáze atd…) má to takhle v normálu být, nebo se dělá nějaký mezikrok, který určí co která komponenta potřebuje pro svůj chod?
- Ot@s
- Backer | 476
Chodilo by to, kdybys protected $model
změnils na
public $model
(v BasePresenter).
Obecně logika je v komponentě je správný přístup. To je princip DI, kdy komponentám (obecně objektům), vkládáš na vstup to, co potřebují k „samostatnému“ životu (konstuktorem, setterem, atributem). Typickým případem je právě tvůj problém – tj. přenesení objektu modelu (nebo DB connection) do komponenty. Opět máš více způsobů, jak to udělat. Můžeš to udělat způsobem, který jsi použil. Dále můžeš využít možností nového konfigurátoru, kdy si tyto závislosti mezi objekty definuješ v config.neon.
Kolem DI už toho bylo hodně napsáno. Výsledky, resp. best practices jsou v dokumentaci a videích z PS.