Dependency Injection ve 2.1: sloučení factories a services

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Grudl
Nette Core | 8227
+
0
-

(Navazuji na starší příspěvek)

V současnosti lze definovat v DIC dva typy entit: služby a továrničky. Rozdíl je v tom, jestli se instance služby uchovává a je dostupná přes metodu getService, nebo se pokaždé vytvoří nová při volání metody create.... Továrničky tak mohou mít navíc i parametry. A compiler umí také vytvářet implementace továrniček definovaných rozhraním.

Uvažuji nad tím, že bych rozdíl mezi obojím zrušil. Vše by se definovalo v jedné sekci services, takže nebude potřeba přemýšlet nad tím, jestli jde o službu nebo továrnu. Rozdíl by spočíval pouze na uživateli, jestli by k entitě přistupoval přes getService() nebo createService().

Narazil jsem na jediný problém, a to je nejasnost v konfiguraci při odkazování se na jinou službu:

services:
	a: MyClass
	b: OtherClass(@a)

Pokud se služba @a nacházela v sekci factories, znamenal odkaz @a zavolání této továrny a do konstruktoru OtherClass se předala nově vytvořená instance MyClass.

Pokud sekce sloučíme, @a bude znamenat klasický odkaz na sdílenou instanci služby a tedy i BC break. Způsob, jak docílit vytvoření nové instance, je krkolomnější: @container::createService(a)

hrach
Člen | 1838
+
0
-

+1

Elijen
Člen | 171
+
0
-

Co zavést nějaký nový symbol namísto ‚@‘? Navrhuji ‚❤‘ :-)

MartinitCZ
Člen | 580
+
0
-

+1

enumag
Člen | 2118
+
0
-

+1

Editoval enumag (23. 4. 2013 20:31)

Honza Marek
Člen | 1664
+
0
-

To mi zní jako zrušení factories bez náhrady. Jsem pro.

Filip Procházka
Moderator | 4668
+
0
-

Moc to nechápu… Bavíme se zde pouze o sloučení sekcí? „implement“ by fungovalo dál?

Btw, již teď používám

services:
	articles:
		class: App\Articles(@doctrine.dao(App\Article))

factories:
	doctrine.dao:
		class: Kdyby\Doctrine\EntityDao
		create: @entityManager::getRepository(%entityName%)
		parameters: [entityName]

Napadá mě tedy, pokud chci předat novou instanci služby (pokud by se sloučily ty sekce), tak by se to dalo napsat takto

services:
    a: MyClass
    b: OtherClass(@a()) # nová instance
    c: AnotherClass(@a) # sdílená instance

Ale @container::createA() bych asi taky přežil :)

David Grudl
Nette Core | 8227
+
0
-

Honza Marek napsal(a):

To mi zní jako zrušení factories bez náhrady. Jsem pro.

Factories se pochopitelně zachová, přesněji rozšíří ;)

Filip Procházka napsal(a):

Napadá mě tedy, pokud chci předat novou instanci služby (pokud by se sloučily ty sekce), tak by se to dalo napsat takto

Jde skutečně jen o sloučení sekcí.

Pokud má služba @a parametry, pochopitelně by se volala jako továrna. Problém je, pokud parametry nemá. Pak je při současné implementaci velmi komplikované rozlišit mezi @a a @a().

Šaman
Člen | 2662
+
0
-

Jak tohle teď vypadá?
Oproti 2.10 mi v @dev nefunguje $container->createFoo();, pokud mám foo v sekci factories.

Našel jsem tohle vlákno, přesunul továrny do sekce services a začal je vytvářet pomocí $container->createService('foo') a to mi zase nefunguje, protože všechny komponenty potřebují v konstruktoru nějaký kontejner a ono se jim to snaží vnutit nějaký z configu. A těch je tam spousta.

Nakonec jsem nevím proč zkusil přesunout definici továren zpět do sekce factories a vytvářet je pomocí createService() a vypadá to, že to funguje.. ale je to dost WTF. Je to už finální stav, nebo se to ještě bude měnit?

Filip Procházka
Moderator | 4668
+
0
-

Pokud někde vytváříš potomky Nette\ComponentModel\Component, tak bych důrazně doporučoval překrýt konstruktor, aby nesomroval ty defaultní parametry (parent a name).

Šaman
Člen | 2662
+
0
-

No, komponenty mám v configu a v továrničce je sosám pomocí $container->createService($name). Co myslíš tím překrýt konstruktor? Vždyť v konstruktoru komponenty přece nemám k dispozici parenta, ne? (pokud si ho nenechám předat parametrem). A $name vlastně taky ne.

Editoval Šaman (4. 6. 2013 5:04)

Filip Procházka
Moderator | 4668
+
0
-

Myslím tím prosté

public function __construct()
{
	parent::__construct(); // ha, už o nich DIC neví
}
Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Ústupek autowiringu, tak říkajíc.

pekelnik
Člen | 462
+
0
-

Především ústupek logice ;) V již zmíněné konfiguraci nebo například v testu mě vůbec nezajímá nějaký parent ;) Takže vlastně nikdy…

Honza Marek
Člen | 1664
+
0
-

Nutí někdo autowiring, aby cpal služby i do nepovinných parametrů? Podle mě by to neměl dělat.

Filip Procházka
Moderator | 4668
+
0
-

vojtech.dobes napsal(a):

Ústupek autowiringu, tak říkajíc.

Především plus pro api třídy. V konstruktoru tohle imho stejně nemá co dělat. Ale to už jsme OT :)

Šaman
Člen | 2662
+
0
-

Filip Procházka napsal(a):

Myslím tím prosté

public function __construct()
{
	parent::__construct(); // ha, už o nich DIC neví
}

Díky, tohle v BaseControlu řeší problém.

Chápu to tedy tak, že i když sekce factories asi z důvodu zpětné kompatibility funguje postaru, tak doporučované je mít všechno v services a služby od továren rozlišovat až při použití – getService() vs. createService()?