[2011–05–05] Finalizace Dependency Injection

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Honza Marek
Člen | 1664
+
0
-

HosipLan napsal(a):

Když je nějaké služba, která nepotřebuje (čti nesmí) vidět všechny služby, tak je vhodnější vytvořit novou instanci Containeru, předat do ní jen pár služeb a tu pak předat jako „kontext“ dané službě.

To je krásný antipattern, který je v Nette hojně využívaný. Samozřejmě hezčejší by bylo, kdyby ta služba měla do sebe předané přes konstruktor nebo settery už přímo potřebné služby nebo nějaké továrničky na ně (kdyby bylo potřeba línou inicializaci).

Filip Procházka
Moderator | 4668
+
0
-

Kdyby to bylo na mě, tak bych všem nutil jednu instanci a popř. předával jenom konkrétní služby. Jenom vysvětluju jak to teď funguje :)

xificurk
Člen | 121
+
0
-

HosipLan napsal(a):

Když je nějaké služba, která nepotřebuje (čti nesmí) vidět všechny služby, tak je vhodnější vytvořit novou instanci Containeru, předat do ní jen pár služeb a tu pak předat jako „kontext“ dané službě.

„Tohle“ mi právě moc nejde do hlavy (vytvářet nový objekt jen proto, abych do něj zkopíroval odkazy na služby z nějakého globálního kontejneru). Protože jednak z obecného hlediska (zaměnitelnosti implementací) nevím, jaké všechny služby bude ten konkrétní objekt, co zrovna vytvářím, potřebovat; druhak, pokud si nějaká implementace bude chtít šáhnout na nějakou službu, o které jsem původně usoudil, že ji nepotřebuje/nesmí na ni šahat, tak toho stejně nakonec nějak dosáhne… jen trochu krkolomněji. Prostě izolace jednotlivých služeb je tak trochu dvousečná zbraň.
Další věc je, že většina služeb jsou typicky singletony (v rámci celé aplikace) a jejich jedinečnost se dost blbě hlídá ve chvíli, kdy začnu tvořit nové kontejnery pro jednotlivé služby.
Čímž rozhodně nechci tvrdit, že obecně více kontejnerů nemá smysl – rozhodně mě napadají místa, kde se skvěle uplatní: více různých připojení do databáze/kešování na různá místa, testování… jen moc nevidím ten zde tolik opěvovaný přínos.

Filip Procházka
Moderator | 4668
+
0
-

Jestli jsem špatně pochopil, jak to TEĎ funguje v Nette, tak mě opravte. Samozřejmě jsem zastáncem jednoho containeru, pro celý životní cyklus Application a služby související (fakt nemám sílu cokoliv obhajovat), protože v tomhle dělení vidím jenom přínos pro omezení počtu parametrů v konstruktoru za cenu dvou containerů.

Kde mi dává smysl více Containerů, pak tady Doctrine\Container, ale to je zase trošku jiná pohádka..

Beztak se teď David doma chytá za čelo a říká si, že jsme to zase nepochopili :)

Ondřej Mirtes
Člen | 1536
+
0
-

Je to přesně tak. Pokud nějaká služba přijímá kontejner (svůj „kontext“), tak nevím, čím ho mám vlastně naplnit a musím jít zkoumat její zdrojáky. Vím, že jsme toto řešení do Nette s Mediem prosazovali, ale v té době se vše řešilo přes Environment, takže to byl krok kupředu. Je potřeba jít ale ještě dál :)

Správné řešení je explicitní vyjádření konkrétních závislostí tím, že je služba přijímá v konstruktoru, případně pro jednorázové použití v metodách.

(Setter injection je blbost a berlička pro případ, že konstruktor je už něčím obsazen. Tohle dělá špatně např. třída RobotLoader, která je závislá na CacheStorage, ale přijímá ho pomocí setteru a ne konstruktoru.)

Kontejner by měl být přístupný pouze na pár speciálních místech – napadají mě cron skripty, testy a PresenterFactory.

Doufám, že se na tohle David chystá.

Patrik Votoček
Člen | 2221
+
0
-

Mě smysl dávají „sub-kontejnery“ právě třeba na připojení k DB.

Co se týká aplikačního kontejneru tak ten vidím jako takovou náhradu za constructor/setter/getter injection. Aneb neposíláte přímo služby ale jejich kontejner.

David Grudl
Nette Core | 8153
+
0
-

Honza Marek napsal(a):

To je krásný antipattern, který je v Nette hojně využívaný.

Hojně = 1× v Nette\Application\Application?

Samozřejmě hezčejší by bylo … nebo nějaké továrničky na ně (kdyby bylo potřeba línou inicializaci).

A jak by taková implementace předávání továrniček místo služeb vypadala? Třeba jako současný DI\Container? ;-)

xificurk napsal(a):

Protože jednak z obecného hlediska (zaměnitelnosti implementací) nevím, jaké všechny služby bude ten konkrétní objekt, co zrovna vytvářím, potřebovat;

To právě vědět musíš. Ať už služby předáváš konstruktorem nebo přes settery, výčet služeb je jasný, jde o sumu všech parametrů.

Čímž rozhodně nechci tvrdit, že obecně více kontejnerů nemá smysl – rozhodně mě napadají místa, kde se skvěle uplatní: více různých připojení do databáze/kešování na různá místa, testování… jen moc nevidím ten zde tolik opěvovaný přínos.

Přínos to má pouze pro ty, kteří to chtějí využívat (a vidí v tom přínos). Z hlediska běžného a většinového uživatele se vůbec nic nemění. Pokud jsi dosud nad DI v Nette neuvažoval, nemusíš ani teď, ono pod kapotou běží zcela automaticky.

Patrik Votoček
Člen | 2221
+
0
-

David Grudl napsal(a):

Hojně = 1× v Nette\Application\Application?

  • Nette\Http\User :-)
David Grudl
Nette Core | 8153
+
0
-

Ondřej Mirtes napsal(a):

Je to přesně tak. Pokud nějaká služba přijímá kontejner (svůj „kontext“), tak nevím, čím ho mám vlastně naplnit a musím jít zkoumat její zdrojáky.

V tom případě vytváříš služby špatně, co ti na to mám říct.

Vím, že jsme toto řešení do Nette s Mediem prosazovali, ale v té době se vše řešilo přes Environment, takže to byl krok kupředu. Je potřeba jít ale ještě dál :)

Ale kdepak, problém byl v $presenter = new $presenterClass v Application, což vyřešil Honzův PresenterFactory.

(Setter injection je blbost a berlička pro případ, že konstruktor je už něčím obsazen. Tohle dělá špatně např. třída RobotLoader, která je závislá na CacheStorage, ale přijímá ho pomocí setteru a ne konstruktoru.)

Naprostý nesmysl. Setter injection zčitelňuje kód.

Kontejner by měl být přístupný pouze na pár speciálních místech – napadají mě cron skripty, testy a PresenterFactory.

Tak konkrétně: kde všude v Nette vadí kontejner?

David Grudl
Nette Core | 8153
+
0
-

Patrik Votoček napsal(a):

  • Nette\Http\User :-)

Jenže tam se zcela záměrně předávají ty továrničky.

Mě by vážně zajímalo, jak by Honza s Ondrou přepsali celé DI v Nette k obrazu svému. Asi by nahradili container v Application za constructor setter (změna na 5 řádků s čistě akademickým smyslem a nulovým přínosem) a pro Nette\Http\User by vyrobili nějaké řešení, které by bylo tak podobné na DI\Container, že by to při dalším refaktoringu sloučili. No a jakmile vznikne potřeba přidat lazy službu do Application (což je v plánu), tak by zase revertli Application na kontejner. Tedy by došli ke stávající podobě. Ale jestli se v něčem šeredně mýlím, opravte mě.

Ve současné implementaci chybí jen jediné: chybějící volání checkServiceType v kontruktorech Application a User.

Honza Marek
Člen | 1664
+
0
-

David Grudl napsal(a):

Ondřej Mirtes napsal(a):

Je to přesně tak. Pokud nějaká služba přijímá kontejner (svůj „kontext“), tak nevím, čím ho mám vlastně naplnit a musím jít zkoumat její zdrojáky.

V tom případě vytváříš služby špatně, co ti na to mám říct.

Jak mi tedy vysvětlíš, že když jsem chtěl zjistit, které služby potřebuje Nette\Http\User, musel jsem se podívat do zdrojáku? :)

David Grudl
Nette Core | 8153
+
0
-

Protože tam chybí phpDoc. Pošleš patch?

Honza Marek
Člen | 1664
+
0
-

Proč jsou vlastně ty authorizator a authenticator líný? Jaký je rozdíl mezi instanciací těchto dvou a nějakýho containeru?

xificurk
Člen | 121
+
0
-

David Grudl napsal(a):

xificurk napsal(a):

Protože jednak z obecného hlediska (zaměnitelnosti implementací) nevím, jaké všechny služby bude ten konkrétní objekt, co zrovna vytvářím, potřebovat;

To právě vědět musíš. Ať už služby předáváš konstruktorem nebo přes settery, výčet služeb je jasný, jde o sumu všech parametrů.

…nebo přes spešl kontejner jako např. Nette\Http\User, že?

Patrik Votoček
Člen | 2221
+
0
-

David Grudl napsal(a):

Ve současné implementaci chybí jen jediné: chybějící volání checkServiceType v kontruktorech Application a User.

A tagy :-)

Ondřej Mirtes
Člen | 1536
+
0
-

David Grudl napsal(a):
V tom případě vytváříš služby špatně, co ti na to mám říct.

Špatně? Jak mám zvenku odhadnout, jaké má ty služba závislosti, když přijímá pouze DI kontejner? (který takhle zaujímá pozici ServiceLocatoru).

Ale kdepak, problém byl v $presenter = new $presenterClass v Application, což vyřešil Honzův PresenterFactory.

Tohle je obecný problém jakéhokoli místa, kde je operátor new. Jakmile je někde v kódu natvrdo new, nijak na tom místě tu napevno vytvářenou implementaci ničím nenahradíš. Proto jsem navrhoval, že by celé Nette mělo vnitřně fungovat na konfigurovatelném DI kontejneru, což nyní částečně supluje pole $defaultServices.

To, jak PresenterFactory zpříjemnila práci, značí, že by se z toho měl stát obecný princip pro všechno ve frameworku. Protože chci mít možnost cokoli nahradit vlastní implementací a vědět, kam kvůli tomu mám sáhnout.

Naprostý nesmysl. Setter injection zčitelňuje kód.

Může ho zčitelnit, pokud má služba 150 závislostí. To je ale bad code smell a říká si o refaktoring. Do počtu 3–4 parametrů v konstruktoru je to v pohodě. Problém se setterem je jeho volitelnost. Jak chceš uživateli říct, aby po vytvoření objektu zavolal ještě sadu setterů? Tohle vede k vývoji metodou pokus-omyl. „Hurá, zavolal jsem setCacheStorage a už to jede“. Ale co když tam je ještě druhý setter, jehož nezavolání se projeví až někde na serveru za ostrého provozu (třeba kvůli tomu, že daná vlastnost se využije jen při isProduction nebo za určité konstelace hvězd).

Setter by měl skutečně být volitelný, tzn. objekt by měl fungovat plnohodnotně bez něj. Nedoplním do RobotLoaderu CacheStorage? Fajn, jeho obsah se nebude kešovat, ale jinak bude plnohodnotně fungovat. RobotLoader se neobejde bez CacheStorage? Tak šup do konstruktoru, protože existence toho objektu nedává bez cache smysl.

Kontejner by měl být přístupný pouze na pár speciálních místech – napadají mě cron skripty, testy a PresenterFactory.

Tak konkrétně: kde všude v Nette vadí kontejner?

Viz ta první odpověď. Tímhle užitím děláš z kontejneru service locator. Škoda, žes nebyl na přednáškách Miška Heveryho, tam to moc pěkně vysvětlil a ukázal (prezentované poučky jsou pěkně shrnuté v této sadě článků, doporučuji). Jde o to, že tím, že objekt příjímá service locator lže o svých závislostech. Prostě se z toho nijak nedozvím, co ve skutečnosti potřebuje a čím mám tedy service locator naplnit. Důkazem budiž tento dotaz. Proč kód samotného frameworku vyhazuje Fatal Error, když jsem splnil vše, co po mně chtěl?

Editoval Ondřej Mirtes (15. 5. 2011 22:12)

Ondřej Mirtes
Člen | 1536
+
0
-

Cokoli má být lazy a uvnitř objektu, do kterého je to vstřikované, se nevyužije vždy, to bych řešil pomocí továrniček. Takže bych do usera předal AuthorizatorFactory a AuthenticatorFactory, které by volaly new Authorizator, resp. new Authenticator až při $factory->create().

Co se týče Usera, tak bych z něj autorizaci i autentizaci vyhodil úplně, protože mi tam nedává smysl. Musím si do něj předat autentikátor jenom kvůli tomu, aby na něm user zavolal nějakou metodu, kterou na něm mohu zavolat sám. Po Userovi požaduji jen to, aby mi zajistil přihlášení usera, tedy uložení jeho identity do session. Vše ostatní by měly zařizovat jiné objekty.

Porovnejte tyto dva kódy:

$user->setAuthenticationHandler($facebookAuthenticator);
$user->login($uid); // zde se zadem volá FacebookAuthenticator, je to nečitelné

a:

$identity = $facebookAuthenticator->authenticate($uid);
$user->login($identity); // zde se do session uloží to, co tam sám předám

Editoval Ondřej Mirtes (15. 5. 2011 22:20)

redhead
Člen | 1313
+
0
-

Ondřej Mirtes napsal(a):

Může ho zčitelnit, pokud má služba 150 závislostí. To je ale bad code smell a říká si o refaktoring. Do počtu 3–4 parametrů v konstruktoru je to v pohodě. Problém se setterem je jeho volitelnost. Jak chceš uživateli říct, aby po vytvoření objektu zavolal ještě sadu setterů? Tohle vede k vývoji metodou pokus-omyl.

Nemůžu než souhlasit. Tesat do monitoru.

David Grudl
Nette Core | 8153
+
0
-

Ondřej Mirtes napsal(a):

Cokoli má být lazy a uvnitř objektu, do kterého je to vstřikované, se nevyužije vždy, to bych řešil pomocí továrniček. Takže bych do usera předal AuthorizatorFactory a AuthenticatorFactory, které by volaly new Authorizator, resp. new Authenticator až při $factory->create().

A jak bys zajistil, že takto vytvořený autorizátor bude singleton v nějakém scope, tj. budeš ho chtít předat ne do jednoho objektu User, ale do více objektů?

Špatně? Jak mám zvenku odhadnout, jaké má ty služba závislosti, když přijímá pouze DI kontejner? (který takhle zaujímá pozici ServiceLocatoru).

Pokud není možné předávat explicitně služby a trváš na předávání kontejneru (zdůrazňuji, že volba je na tobě) můžeš použít typehint a předat statický kontejner. V případě dynamického lze závislosti uvést v dokumentaci a kontrolovat pomocí checkServiceType.

Tohle je obecný problém jakéhokoli místa, kde je operátor new. Jakmile je někde v kódu natvrdo new, nijak na tom místě tu napevno vytvářenou implementaci ničím nenahradíš. Proto jsem navrhoval, že by celé Nette mělo vnitřně fungovat na konfigurovatelném DI kontejneru, což nyní částečně supluje pole $defaultServices.

Ale tak to přece funguje odjakživa, celé Nette je konfigurovatelné pomocí systémového kontejneru, ten je konfigurovatelný pomocí config.neon.

A pokud tím celé Nette myslíš jako odstranit úplně všechny new, tak sorry, ale předávat v konstruktoru seznam tříd výjimek, abych měl full-DI i třeba na výjimku InvalidArgumentException, tak to je nesmyslná úchylárna.

Pokud jsi narazil na konkrétní případ, kde by bylo vhodné nahradit new za DI, tak ho konkrétně zmiň, jinak je to prázdné třepání.

Do počtu 3–4 parametrů v konstruktoru je to v pohodě.

Jasně, $obj = new Object($argX, $argB, $arg7, $argXy) je úžasně srozumitelné, jasné jak facka, zatímco $obj->setTemplateFilter($argX)->setCacheStorage($argB)... je bad smell, fuj, špatně, ostuda, Miško Hevery se obrací v posteli ;)

Tak konkrétně: kde všude v Nette vadí kontejner?

Ptám se znovu, kde ti vadí? Našel jsi 1 případ, třídu User? Hrůza, tak to je celý framework na odpis! :-)

David Grudl
Nette Core | 8153
+
0
-

Už začínám být zoufalý z těch neustálých řečí, počínaje „Nette nemá DI“, přes „všechno je blbě, bad smell, hojný antipattern“ až po „v Nette to musíš dělat tak a ne jinak.“ To přece není vůbec žádná pravda! Chjo.

Navíc se tu formují dvě protichůdné skupiny, jedni měsíce naříkají, proč má Application jiný kontext než Environment, druzí kontranaříkají, že vůbec má nějaký kontext…

Takže:

  1. pokud vytváříte objekt, předávejte mu jeho závislosti jako instance konkrétní objektů (via konstruktor nebo přes settery)
  2. teprve když to vážně nebude možné, vytvořte statický kontejner (potomek DI\Container)
  3. nad ničím dalším neuvažujte, neřešte, nepřepínejte ;-) na DI se takřka nic nemění a bude fungovat stejně transparentně, jako dosud.
VasekPurchart
Člen | 20
+
0
-

Davide asi chápu kam tím míříš – nechceš asi nikomu nařizovat jak má kdo svůj kód přesně psát (vynucení constructor injection, použití kontextu jako Service Locator), chápu to správně? Jestli ano, tak s tím jednoznačně souhlasím, ale zároveň si taky myslím, že Nette samotné by mělo být napsáno tak, aby reprezentovalo ty nejčistší možné volby. – Constructor Injection a důkladné vyjmenovávání služeb (ne kontext/container/w/e).

Dobrým příkladem je právě RobotLoader, jak uváděl Ondra, s tím mám osobní zkušenosti.

Cifro
Člen | 245
+
0
-

Tak ako by som sa potom zbavil tohto Environment::getCofing()? (Ide o triedu z tutoriálu z Kuchařky.) Potrebujem do služby dostať údaje z configu.

Služba sa definuje v config.neon

service:
	ModelLoader: Proj\ModelLoader

Podľa prvého bodu ma to nenapadá, a pri druhom treba urobiť aj tovarničku napr. ako tuto – tomu by som sa chcel vyhnúť.

Sice je to dosť lamerský dotaz, ale možno nebude naškodu aj pre ostatných vidieť nejakú ukážku ako to urobiť s týmto „novým“ DI.

Editoval Cifro (15. 5. 2011 23:54)

Ondřej Mirtes
Člen | 1536
+
0
-

Pokud chci nějaký objekt mít vytvořený lazy a zároveň singleton, tak ta továrnička může vytvářet/vracet jedinou instanci.

class SingletonAuthenticatorFactory
{

	private $instance;

	public function create()
	{
		if ($this->instance == NULL) {
			$this->instance = new Authenticator();
		}
		return $this->instance;
	}
}

Konstruktor vs. setter:

Jak mám vědět, že po konstruktoru musím volat ještě setTemplateFilter a setCacheStorage? Navíc bych čitelně napsal new Object($cacheStorage, $templateFilter) a nešifroval bych to do $argX proměnných :)

config.neon:

Tady jsem navrhoval jen to, že by se mi líbilo, kdyby $defaultServices bylo nahrazeno nějakým nette.neon přímo ve frameworku, aby pro tu samou věc neexistovala dvojí syntaxe. Do tohoto configu by se pak mergovaly uživatelské configy, ve kterých by se mohla ta nastavení překrýt.

new:

To samozřejmě nemůžeš aplikovat na výjimky, ty nahrazovat nechceš :)

Já vůbec neříkám, že je Nette na odpis, ale že ten mnou prezentovaný přístup mi přijde správný a univerzální, tak bych ho rád sjednotil napříč celým frameworkem. Proč Template nedostává celý kontejner, ale jen Translator setterem? Proč jiné objekty dostávají celý kontejner? Chci zabránit těmto situacím, ke kterým, jakmile si něco z jádra Nette sestavuji ručně (Application, Presenter, Control), dochází často.

David Grudl
Nette Core | 8153
+
0
-

manik napsal(a):

Davide asi chápu kam tím míříš – nechceš asi nikomu nařizovat jak má kdo svůj kód přesně psát (vynucení constructor injection, použití kontextu jako Service Locator), chápu to správně?

Přesně tak. A když už by se mě někdo zeptal, tak bych mu řekl, že service locator má zvolit jako krajní možnost.

Jestli ano, tak s tím jednoznačně souhlasím, ale zároveň si taky myslím, že Nette samotné by mělo být napsáno tak, aby reprezentovalo ty nejčistší možné volby.

Jsem přesvědčen, že tak tomu (limitně) je.

  • Constructor Injection a důkladné vyjmenovávání služeb (ne kontext/container/w/e).

Dobrým příkladem je právě RobotLoader, jak uváděl Ondra, s tím mám osobní zkušenosti.

Má zkušenost zase říká, že setter injection vede k lépe čitelnému kódu, příklad jsem tu uvedl. Ale dejme tomu, že je to diskutabilní. Najdeš jiný případ krom RobotLoaderu, zmíněného User (kde zatím nikdo neuvedl ekvivalentní jiné řešení) a Application? Z těch všech řečí mám totiž pocit, že takových příkladů jsou tam desítky a desítky.

David Grudl
Nette Core | 8153
+
0
-

Ondřej Mirtes napsal(a):

Pokud chci nějaký objekt mít vytvořený lazy a zároveň singleton, tak ta továrnička může vytvářet/vracet jedinou instanci.

Teď ji ještě uprav tak, aby byla konfigurovatelná a dostupná ze systémového kontextu (např. přes Environment::getContext()->getService('authenticator')).

Tady jsem navrhoval jen to, že by se mi líbilo, kdyby $defaultServices bylo nahrazeno nějakým nette.neon přímo ve frameworku, aby pro tu samou věc neexistovala dvojí syntaxe.

Neumím si představit, jak by se zapisoval kód některých továrniček v neonu.

Já vůbec neříkám, že je Nette na odpis, ale že ten mnou prezentovaný přístup mi přijde správný a univerzální, tak bych ho rád sjednotil napříč celým frameworkem. Proč Template nedostává celý kontejner, ale jen Translator setterem? Proč jiné objekty dostávají celý kontejner?

Chování je jednotné.

Filip Procházka
Moderator | 4668
+
0
-

Davídku, udělej nám zase kousek, ať se nám to pohne :) Já úplně slintám na to, až tam budou tagy, vyměnitelnost Configuratoru a ContainerBuilder/Compiler :) Jestli se ti nechce, tak to spatláme, že :)

Každý by mohl poslat pár pull requestů s úpravou toho co se mu nelíbí, s přiloženým RFC a pak na PS půjčíme Davidovi MacBook a všichni budou spokojení :)

Editoval HosipLan (16. 5. 2011 8:48)

Nox
Člen | 378
+
0
-

Nevim jestli se teď Davidovi bude chtít takovým plantážníkům něco vytvářet :)

David Grudl
Nette Core | 8153
+
0
-

HosipLan napsal(a):

Davídku, udělej nám zase kousek, ať se nám to pohne :) Já úplně slintám na to, až tam budou tagy, vyměnitelnost Configuratoru

Vyměnitelnost Configuratoru by byla úplná revoluce. Ale nedám ji tam.

Filip Procházka
Moderator | 4668
+
0
-

Já tak rád slovíčkařím :) https://github.com/…tte/pull/242 Něco takového jsem myslel… Ale tohle je asi ta poslední věc a dá se bez toho žít

Patrik Votoček
Člen | 2221
+
0
-

:-DDDD ale líbilo by se mě kdyby byl konfigurátor reprezentován interfacem a né třídou

David Grudl
Nette Core | 8153
+
0
-

Zajímalo by mě, k čemu konkrétně v praxi potřebuješ použít vlastní Configurator. (kvůli zamýšlené úpravě)

Patrik Votoček
Člen | 2221
+
0
-

Třeba kvůli tomu že si chci přidat kompilátory. Pak taky snadno nahradit Nette\DI\Context za jinou chytřejší třídu.

Hlavní je přesunout továrničky z konfigurátoru jinam a z konfigurátoru udělat Nette\DI\ContainerBuilder. Nebo naopak ponechat konfigurátor a Nette\DI\ContainerBuilder přidat.

Editoval Patrik Votoček (16. 5. 2011 15:47)

David Grudl
Nette Core | 8153
+
0
-

Jelikož Configurator má prakticky za jediný úkol vyrobit systémový context (tj Environment::getContext(), přesouvat tento úkol jinam nedává moc smysl.

Místo výměny konfigurátorů se mi zdá pružnější umožňit použití vlastního kontextu (tj. přidat Environment::setContext()).

ContainerBuilder je obecná třída pro práci nad obecným kontejnerem. Zřejmě ji do frameworku přidám, aby uměla načíst třídy z pole a případně vygenerovat PHP cache.

Patrik Votoček
Člen | 2221
+
0
-

David Grudl napsal(a):

Jelikož Configurator má prakticky za jediný úkol vyrobit systémový context (tj Environment::getContext(), přesouvat tento úkol jinam nedává moc smysl.

Ano to chápu ale já třeba v Nella Frameworku používám / chci používat trochu jiné výchozí nastavení systémového kontextu. A dědit od třídy která obsahuje továrničky (tj. zbytečný balast který nepotřebuju) mě připadá zbytečné a né zrovna správné.

Místo výměny konfigurátorů se mi zdá pružnější umožňit použití vlastního kontextu (tj. přidat Environment::getContext()).

Environment::getContext() už je né? spíš jsi chtěl říct Environment::setContext() nebo se mýlím?

ContainerBuilder je obecná třída pro práci nad obecným kontejnerem. Zřejmě ji do frameworku přidám, aby uměla načíst třídy z pole a případně vygenerovat PHP cache.

jde mě o něco jako jsem popsal tady: https://forum.nette.org/…cy-injection#… v Symfony 2 to myslím není IConfigurator ale ICompiler.

David Grudl
Nette Core | 8153
+
0
-

Jasně, setContext(). Prostě nemusíš vůbec Configurator dědit. Obecně vzato, vůbec nemusíš používat ani třídu Environment, ani třídu Configurator a rovnou pracovat s vlastním DI kontejnerem.

Patrik Votoček
Člen | 2221
+
0
-

Já ale nechci pracovat s vlastním kontejnerem nýbrž nahradit systémový za svůj vlastní.

Tharos
Člen | 1030
+
0
-

Trochu odbočím /respektive vrátím se k jádru tématu ;)/. Všiml jsem si, že kontextu předávanému Application se z „globálního“ kontextu předává služeb vcelku poskrovnu. Pokud jich chci předat více /například cacheStorage, abych nemusel pro přístup ke cache všude volat Environment::getCache() a měl vše hezky cool DI a mohl se v hospodě chvástat, jak nikde v aplikaci nepoužívám třídu Environment ;)/, plus bych si rád do contextu Appliction předal i například službičku config (mám v neonu i řadu nastavení, se kterými pracují komponenty a podobně), tak mi nezbývá, než si nadefinovat úplně vlastní createApplication:„https://api.nette.org/2.0/source-common.Configurator.php.html#299“ (a skoro shodnou s původní, jen doplněnou o předání těch několika dalších služeb z globálního kontextu) a používat tu. Chápu to správně?

A zároveň, jestli to tedy dobře chápu, je toto v podstatě nejsnazší způsob, jak v duchu DI používat něco z config.neon (jak se tu na fóru teď někdo někde ptal). Je to významný krok kupředu, dobrá práce!

Jo a upozorňuji, že svůj dotaz nezamýšlím jako nějakou skrytou kritiku nebo tak :), nový koncept nemám problém přijmout za svůj a chápu jeho výhody.

Patrik Votoček
Člen | 2221
+
0
-

Tharos napsal(a):

Všiml jsem si, že kontextu předávanému Application se z „globálního“ kontextu předává služeb vcelku poskrovnu. … (mám v neonu i řadu nastavení, se kterými pracují komponenty a podobně)

Pozor ale do Presenteru (potažmo komponent) je předáván celý systémový kontainer. Tenhle "skromný je jenom v Application :-)

Editoval Patrik Votoček (16. 5. 2011 23:55)

David Grudl
Nette Core | 8153
+
0
-

Pokud zrovna nevytváříš potomka třídy Application, tak žádné další služby by sis do něj přidávat neměl. On je nepotřebuje. Je to totéž, jako zavolat funkci s více parametry, než očekává / přijímá. Nemá to žádný efekt.

Služby si tedy předávej přímo tam, kde je budeš potřebovat. Do presenteru například pomocí PresenterFactory.

Tharos
Člen | 1030
+
0
-

Díky moc vám oběma za nakopnutí, konečně mi to všechno secvaklo a zapadlo hezky dohromady.


A zvažte lock tohoto vlákna, protože když už to secvaklo i mně, tak to už asi opravdu musely být všechny smysluplné otázky položeny a zodpovězeny ;).

Patrik Votoček
Člen | 2221
+
0
-

navrhuji public Application::getContext() na protected nebo úplně zrušit

Editoval Patrik Votoček (17. 5. 2011 0:39)

Filip Procházka
Moderator | 4668
+
0
-

Jó to dává smysl! :) Protože to tady dost lidí mate…

//edit: spíš protected, co kdybych chtěl dědit…

Editoval HosipLan (17. 5. 2011 1:16)

Patrik Votoček
Člen | 2221
+
0
-

Ještě mě tak napadá je v plánu aby Environment::

  • setVariable
  • getVariable
  • getVariables
  • expand
  • getService
  • getHttpRequest
  • getHttpResponse
  • getHttpContext
  • getApplication (tady si nejsem úplně jistý)
  • getUser
  • getRobotLoader
  • getCache
  • getSession
  • getConfig

vyhazovaly deprecated nebo byly rovnou odstraněny?

David Grudl
Nette Core | 8153
+
0
-

V plánu není. Environment je statická obálka nad systémovým kontejnerem. Zbytečné jsou teď jen getVariable a getConfig, které dělají to stejné.

David Grudl
Nette Core | 8153
+
0
-

Doplnil jsem do prvního příspěvku informaci o používání tagů.

arron
Člen | 464
+
0
-

Tharos napsal(a):

Díky moc vám oběma za nakopnutí, konečně mi to všechno secvaklo a zapadlo hezky dohromady.


A zvažte lock tohoto vlákna, protože když už to secvaklo i mně, tak to už asi opravdu musely být všechny smysluplné otázky položeny a zodpovězeny ;).

Jeste ne, protoze me to porad jeste tak uplne do sebe nezapadlo :-) Ale predpokladam, ze po vydani finalni verze k tomu bude podrobna dokumentace (?) :-)

Filip Procházka
Moderator | 4668
+
0
-

Všecko co potřebuješ vědět je přece v úvodním příspěvku, nebo v odkazovaných vláknech. Pokud to nechápeš tak si asi ještě nedošel do stádia „týjo! to DI je cool! to chci teď používat!“ a můžeš s klidem dál pracovat jako do teď :)

arron
Člen | 464
+
0
-

Coz o to, k tomu jsem dospel uz relativne davno, spis mam problem pochopit jeho fungovani v nette :-)

Filip Procházka
Moderator | 4668
+
0
-

Na DI není vůbec nic magického, nebo složitého. Je to jenom pár jednoduchých principů, které když dodržíš, tak budeš mít čitelnější a lépe testovatelný kód. Mno a jako bonus tu je DI\Container, který pomáhá služby sestavovat a nastavovat. That's all folks :)