Komponenty v DIC pomocí nových továrniček
- Filip Procházka
- Moderator | 4668
Nedávno jsem tu zakládal flame, jak mít komponenty v DI Containeru. Doporučil bych pročíst, je tam spousta zajímavých postřehů.
Ovšem teprve s novým-novým DIC to teprve dává smysl! Všimli jste si
také těch factories ? Možná
vám taky, jako mně, nesedělo že bych si předával $context
napříč modely a vytvářel si z něj entity. Divné by to bylo. Ale kde to
dává smysl, tak to jsou komponenty.
Předvedu na příkladu:
factories:
comp1:
class: MyComponent
A v presenteru
protected function createComponentComp()
{
return $this->getContext()->createComp1();
}
Naprostá bomba, že? Funguje v nich všechno, co by šlo nastavit v normální službě. Navíc máte k dispozici možnost nastavit vstupní parametry téhle továrničce a není sdílená. Vytvoří se pokaždé znovu. Což byla hlavní skulinka, kdyby byly komponenty v DIC jako služby.
To stejné jde dělat i s presentery! Stačí si podědit a upravit
IPresenterFactory
, jako inspiraci bych nabídl svoji
implementaci.
Samozřejmě je potřeba překousnout fakt, že contextu se jen tak nezbavíme. Bylo by možné, komponenty do presenterů předávat automaticky už v DIC, třeba takto:
factories:
myPresenter:
class: MyPresenter(@container)
setup:
- [addComponent, [@gridComponent, 'grid']]
- [addComponent, [@paginatorComponent, 'paginator']]
Jenomže tohle nás kompletně odstřihne od jakékoliv možnosti lazy inicializace.
Líbí se mi první varianta, kde si komponenty navazuji v továrničkách a vyrábím v contextu. Ten jeden context v těch presenterech klidně překousnu.
Zahodil jsem TemplateFactory
, protože jsem nakonec pochopil,
že je to hovadina a s matnou představou co by to mohl být ten
templateConfigurator, který zmiňoval @**HonzaMarek**, jsem si udělal
vlastní. Jde o třídu, která k vytvořené instanci šablony přidá
globální makra a helpery.
Jako bonus bych nabídl pár
řádků kódu, který vám pomůže komponenty pěkně sjednotit. Nebavilo
mě totiž na každé komponentě volat ->setParameters()
ikdyž
žádné nemá a nebo ji vždy nastavovat jako ne-sdílenou, vypínat autowire a
předávat templateConfigurator.
Když si tedy ke komponentě přidám tag component
, tak bude
nastavena tak, aby se chovala jako továrnička.
- David Grudl
- Nette Core | 8229
Továrnička pak jde úplně zobecnit na
protected function createComponent($name)
{
return $this->getContext()->components->$name; // nebo nějak podobně
}
A v konfigu by to bylo jako
components:
factories:
signUpForm: ...
- Filip Procházka
- Moderator | 4668
To se mi už ale úplně nelíbí. Protože takhle bych vytvořil jakoukoliv komponentu v jakémkoliv presenteru. Určitě je to tak v pořádku? Jak budu ovládat přístup?
Třeba teď mám
/**
* @return \Kdyby\Components\FrontCmsPanel\NodeDesignerControl
* @Allowed("cms:node", "create")
*/
protected function createComponentNodeDesigner()
{
return $this->getContainer()->createCms_nodeDesigner();
}
A chrání mi to checkRequirements.
Takhle bych se o to připravil.
- uestla
- Backer | 799
David Grudl napsal(a):
Továrnička pak jde úplně zobecnit na
protected function createComponent($name) { return $this->getContext()->components->$name; // nebo nějak podobně }
Neházelo by to, že service neexistuje? Čili by se mělo volat
$container->components->{'create' . $name}();
?
- David Grudl
- Nette Core | 8229
Je potřeba dodat, že používání getContext() je v rozporu s Dependency Injection s výjimkou situace, kdy by samotný presenter byl v roli DI kontejneru. Což on skutečně z určitého pohledu je, problém je v tom, že zároveň plní i jiné úlohy.