Context vs. inject metody
- Freestyler
- Člen | 50
Zdravím,
pár hodin pročítám fórum, hledám na google, ale nedopídil jsem se
výsledku. $this->context je prý zastaralé a nemá se používat, místo
toho má existovat injectování. Něco jsem si k tomu přečetl, ale moc
jasné mi to zatím není.
Konkrétní problém:
BasePresenter
<?php
namespace App\Model;
use Nette;
class Base extends \Nette\Object
{
public $database;
public function __construct(\Nette\Database\Context $database) {
$this->database = $database;
}
public function fetchAll() {
return $this->database->table('articles');
}
}
HomepagePresenter
<?php
namespace AdminModule;
/**
* Homepage presenter.
*/
class HomepagePresenter extends BasePresenter
{
public function renderDefault() {
$this->template->articles = $this->context->articles->fetchAll();
}
}
Jde mi o to, jak se tedy vyhnout contextu a vypsat všechny články z db pomocí injectu.
A je tedy nutnost dále registrovat model jako službu?
- mkoubik
- Člen | 728
namespace AdminModule;
use App\Model\Articles;
class HomepagePresenter extends BasePresenter
{
private $articles;
public function __construct(Articles $articles)
{
$this->articles = $articles;
}
public function renderDefault()
{
$this->template->articles = $this->articles->fetchAll();
}
Službu pořád musíš registrovat v DI kontejneru, jen ji nemusíš pojmenovávat.
services:
- App\Model\Articles
- Freestyler
- Člen | 50
Super, díky. Funguje to.
Ještě se jenom zeptám (protože nerad jen kopíruju kód, ale chci mu rozumět).
Tím konstruktorem
public function __construct(Articles $articles)
si předávám proměnnou $articles do třídy Articles a tam si jí potom jen zavolám. Je to tak?
Je teda škoda, že je to o dost kódu víc, ale v tomhle případu mi to asi nevadí, protože třídu Articles stejně mám. Každopádně jsem to všechno chtěl mít v Base modelu, ale to by asi byl bad-practice cpát vše do jednoho modelu …
- MartinitCZ
- Člen | 580
Tohle je lepší:
namespace AdminModule;
class HomepagePresenter extends BasePresenter
{
/**
* @var \App\Model\Articles
* @inject
*/
public $articles;
public function renderDefault()
{
$this->template->articles = $this->articles->fetchAll();
}
Editoval martinit (21. 6. 2014 20:25)
- Freestyler
- Člen | 50
Super, tohle funguje dobře, ale narazil jsem na další problém. V HomepagePresenteru potřebuju ještě pár dalších funkcí, tam jsem si řekl, že na menu při úpravě článku si udělám továrničku, takže něco jako:
public function createComponentArticleMenu() {
$form = new Form();
$form->addSelect('category','Kategorie', $this->category->getCategory()->fetchPairs('id','category_name'));
return $form;
samozřejmě na začátku souboru mám uvedno public $category, stejně jako public $articles
Továrničku vykresluji klasicky ve view přes {control articleMenu}
Pro úplnost ještě přidám metodu v modelu Articles
public function getCategory() {
return $this->database->table('category');
}
Cílem tohoto je vykreslit rozbalovací menu s názvy kategorií (načtené z db z tabulky category, která je přes cizí klíč category.id propojena na tabulku articles.category).
Zajímavé je, že jakmile prohodím ty dva publicy na začátku, tak ten první funguje a druhý ne. Co dělám špatně?
Případně jestli na toto „ArticleMenu“ jdu úplně špatně budu rád za popostrčení správným směrem.
Díky.
- Freestyler
- Člen | 50
Mám to takhle:
<?php
namespace AdminModule;
use Nette\Application\UI\Form;
/**
* Homepage presenter.
*/
class HomepagePresenter extends BasePresenter
{
/**
* @var \App\Model\Articles
* @inject
*/
public $articles;
public $category;
public function renderDefault()
{
$this->template->articles = $this->articles->fetchAll();
}
public function createComponentArticleMenu() {
$form = new Form();
$form->addSelect('category','Kategorie', $this->category->getCategory()->fetchPairs('id','category_name'));
return $form;
}
}
Zajímavý je, že když v tu továrničku přepíšu takto:
public function createComponentArticleMenu() {
$form = new Form();
$form->addSelect('category','Kategorie', $this->articles->getCategory()->fetchPairs('id','category_name'));
return $form;
}
Tak funguje. (Je tam nahrazeno $this->category za $this->articles. Není možný, že nette nějak umí cizí klíče a dohledá si to? Každopádně mi není jasný proč to nefunguje když si zadefinuju public $category; a v modelu se dotazuju do správný tabulky a chci z ní jen dostat data do presenteru a vypsat je v šabloně …
Editoval Freestyler (24. 6. 2014 23:03)
- Tabetha
- Člen | 140
<?php
namespace AdminModule;
use Nette\Application\UI\Form;
/**
* Homepage presenter.
*/
class HomepagePresenter extends BasePresenter
{
/**
* @var \App\Model\Articles
* @inject
*/
public $articles;
/**
* @var \NamespaceTridyCategory
* @inject
*/
public $category;
public function renderDefault()
{
$this->template->articles = $this->articles->fetchAll();
}
public function createComponentArticleMenu() {
$form = new Form();
$form->addSelect('category','Kategorie', $this->category->getCategory()->fetchPairs('id','category_name'));
return $form;
}
}
nebude to takto fungovať?
- Freestyler
- Člen | 50
Tak to je ještě víc zajímavý. Já mám všechno v modelu Articles (všechno co pracuje se články), tzn. zatím dvě funkce.
Pokud uvedu dvě @inject anotace, tak to začne fungovat, ale to se mi moc nelíbí. Nešlo by to nějak lépe? Přijde mi to jako zbytečné opakování kódu.
/**
* @var \App\Model\Articles
* @inject
*/
public $articles;
/**
* @var \App\Model\Articles
* @inject
*/
public $category;
Předpokládám, že na to budu muset použít inject metody?
Editoval Freestyler (24. 6. 2014 23:38)
- David Matějka
- Moderator | 6445
Pokud to mas vsechno v jedne modelove tride, tak ji injectuj jen jednou…
Editoval matej21 (24. 6. 2014 23:42)
- Freestyler
- Člen | 50
matej21 napsal(a):
Pokud to mas vsechno v jedne modelove tride, tak ji injectuj jen jednou…
Ano to mám, ale pokud tam ten inject neuvedu 2×, tak to nefunguje:
Call to a member function getCategory() on a non-object
A je to vidět už když píšu změnu z articles na category, tak netbeans mi ukáže, že articles patří do App\Model\Articles a category do \AdminModule\HomepagePresenter což je samozřejmě blbost … namespace jsem všude kontroloval a je správně a nefungovalo by to i kdybych tu inject anotaci napsal třeba 100×. Takže problém bude jinde, ale už jsem bez nápadu :(.
A teď babo raď :).
- David Matějka
- Moderator | 6445
Ten model/sluzbu mas injectnutej v property articles, tak pouzivej
$this->articles
Az budes mit nejakou tridu
App\Model\Category
nebo cokoliv, tak si to injectnes do property
categories
- Filip Procházka
- Moderator | 4668
Annotace @inject
není opakování kódu. To je použití
hotového kódu. To je jako bys říkal, že sis napsal třídu s nějakou
funkčností abys ji mohl použít na více místech, ale odmítal jsi dvakrát
napsat new SomeClass
, protože „je to opakování kódu“, což
je hloupost :)