__construct v base presenteru i v ostatních presenterech
- n.u.r.v.
- Člen | 485
Ahoj, potřeboval bych na svých stránkách generovat v záhlaví menu. Menu se bude trochu lišit například podle toho, kde se uživatel nachází, nebo zda li je přihlášený, nebo ne…
Můj plán byl takový, že jsem si na to uděla metodu v MenuReposiotry.php a pak v basepresenteru jsem udělal například toto:
$private $menu;
public function __construct(Model\MenuRepository $menu) {
$this->menu = $menu;
}
public function beforeRender() {
$this->template->leftItems = $this->menu->generateLeftMenu();
$this->template->adminItems = $this->menu->generateAdminMenu();
}
To sice fungovalo, ale do té doby, než jsem si například udělal nějaký jiný presenter, který měl taky __construct(). Při pokusu o načtení se mi dostala chyba: Call to a member function generateLeftMenu() on a non-object.
Jak to vyřešit? Zatím mě napadá jen nepoužívat v basepresenteru __construct, ale použít $this->context->…Ale context se prý už nemá používat… Díky…
EDIT – našel jsem zúsob, ale nevím, zda je to dobré řešení → v basePresenteru místo __construct použít inject…
Editoval n.u.r.v. (13. 11. 2013 14:02)
- David Matějka
- Moderator | 6445
jasne, inject* metody jsou na tohle delany.. pak jeste muzes pouzit @inject anotaci (nevim, v jake je to verzi) nebo @autowired
jinak, pokud je to mozny, tak je casto lepsi si cely menu vyclenit do komponenty
- Casper
- Člen | 253
Injektovat závislosti můžeš do presenteru v Nette 2.1dev třemi způsoby:
Inject anotací:
class UserPresenter extends SecuredPresenter {
/** @var \Model\Facade\PaymentFacade @inject */
public $paymentFacade;
}
Inject metodami:
class UserPresenter extends SecuredPresenter {
/** @var \Model\Facade\PaymentFacade */
public $paymentFacade;
public function inject(\Model\Facade\PaymentFacade $paymentFacade){
$this->paymentFacade = $paymentFacade;
}
}
Konstruktorem:
class UserPresenter extends SecuredPresenter {
/** @var \Model\Facade\PaymentFacade @inject */
public $paymentFacade;
public function __construct(\Model\Facade\PaymentFacade $paymentFacade){
$this->paymentFacade = $paymentFacade;
}
}
V BasePresenteru se samozřejmě konstruktor hodí nejméně, protože tím nutíš všechny podtřídy definovat stejnou závislost a tu předávat ručně. A proto vznikly obě další možnosti.
- MartinitCZ
- Člen | 580
V případě Nette presenterů zapomente, že __constructor exituje!!!
Pokud potřebuješ předávat závislosti, tak anotací @inject, funckcí
injectName(…) a nebo přes $this->context.
- romiix.org
- Člen | 343
martinit napsal(a):
V případě Nette presenterů zapomente, že __constructor exituje!!!
Pokud potřebuješ předávat závislosti, tak anotací @inject, funckcí injectName(…) a nebo přes $this->context.
Z akého dôvodu je „zakázané“ (?!) v presentroch používať konštruktor?
- Casper
- Člen | 253
martinit:
Spíš bych řekl: kontruktor využít jen tehdy, pokud potřebuješ
injectovat nějakou cestu apod, které nemůžeš specifikovat typehint. Tam
prostě jiná volba není, pokud nechceš používat
$this->context
. Nicméně pokud potřebuješ v BasePresenteru
nějakou cestu, context bych volil.
- n.u.r.v.
- Člen | 485
martinit napsal(a):
V případě Nette presenterů zapomente, že __constructor exituje!!!
Pokud potřebuješ předávat závislosti, tak anotací @inject, funckcí injectName(…) a nebo přes $this->context.
Na školení bylo výslovně řečeno, že $this->context už nepoužívat ,ale používat __construct…
- David Matějka
- Moderator | 6445
@martinit: doporucovat $this->context namisto konstruktor injection chce odvahu :))
kratce:
- $this->context skryva zavislosti
- konstruktor je nejlepsi zpusob predani zavislosti, jelikoz neumozni vytvorit instanci bez tech zavislosti
- inject metody a syntactic sugar v podobe @inject anotaci vzniknul jako obrana proti depedency hellu v konstruktoru
- llook
- Člen | 407
Pokud chceš použít constructor injection, tak se to dělá tak, že konstruktor potomka vyžaduje kromě svých vlastních závislostí i všechny závislosti předka:
class ConcretePresenter extends BasePresenter
{
private $otherService;
public function __construct(Model\MenuRepository $menu, SomeOtherService $otherService)
{
parent::__construct($menu);
$this->otherService = $otherService;
}
}
Když přidáš novou závislost do konstruktoru BasePresenteru, tak musíš aktualizovat konstruktory všech jeho potomků, což může být solidní opruz.
Proto existuje možnost injektovat přes inject metody. Často se závislosti
BasePresenteru vkládají přes inject a závislosti potomků přes konstruktor.
Samotný Nette\Application\UI\Presenter
má také spoustu
závislostí, vkládané právě přes inject metodu, aby ses tím v potomcích
nemusel zabývat: Nette\Application\UI\Presenter::injectPrimary().
Není to nejčistší řešení, ale je funkční a celkem použitelné.
- n.u.r.v.
- Člen | 485
matej21 napsal(a):
jasne, inject* metody jsou na tohle delany.. pak jeste muzes pouzit @inject anotaci (nevim, v jake je to verzi) nebo @autowired
jinak, pokud je to mozny, tak je casto lepsi si cely menu vyclenit do komponenty
Ahoj, ještě jsem našel jeden způsob, takže dotaz – který z níže uvedených způsobů je lepší?
1)
abstract class BasePresenter extends Nette\Application\UI\Presenter {
private $menu;
public function injectMenu(Model\MenuRepository $menu) {
$this->menu = $menu;
}
...
...
public function beforeRender() {
$this->template->menu = $this->menu->generateMenu();
}
2)
use Model\MenuRepository;
....
....
abstract class BasePresenter extends Nette\Application\UI\Presenter {
public function beforeRender() {
$menu = new MenuRepository($this->getUser());
$this->template->menu = $menu->generateMenu();
}
}
- romiix.org
- Člen | 343
Záleží od okolitých podmienok. Potrebuješ službu vo viacerích
(ideálne všetkých) potomkoch triedy BasePresenter
? Ak áno,
patrí do ich predka.
Ak by mal byť kód potomka BasePresentru
v metóde
beforeRender()
vždy rovnaký – daj ho do predka, ale nezabudni
na začiatku metódy v potomkoch (ak bueš potrebovať metódu rozšíriť)
volať parent:beforeRender()
.
- David Matějka
- Moderator | 6445
@n.u.r.v.: prvni zpusob je lepsi.. mel by ses co nejvice vyhybat rucnimu instancovani. kdyz budes potrebovat zmenit zavislosti, tak dle druheho zpusobu bys to musel vsude, kde to pouzivas. kdyz to mas jako sluzbu, kterou injectnes, tak se o vse postara di container, pripadne zavislosti doplnis pres neon.