Autowiring ve fasade class

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

Ahoj,

v aplikaci používám Doctrine2 a jeho repository, ale teď jsem se dostal do situace, kdy by se mi hodila Fasade vrstva – místo, kde obsluhovat celé Use Case využívající více repositories…
Má otázka: je možné použít autowiring přes inject metody i na jiných místech, než jsou presentery?
Pokud ne, jak můžu definovat službu v .neon konfigu, tak abych ji definoval jiné služby jako parametr?
Pokud ani toto není možné, jaký můžu použít postup?
Díky a hezký den.

Filip Procházka
Moderator | 4668
+
0
-

Nejprve si přečti tento příspěvek

Přečteno? Super. Takže ve zkratce: jde to ale nedělej to a použij constructor injection.

PirateJack
Člen | 9
+
0
-

Super. Přečteno. Díky. :)
Inject metody v modelu jsou zlo, bo zavádějí nepodmíněné závislosti. (Chápu správně?)
Jak ale můžu definovat službě parametry konstruktoru, tak abych ji předal závislosti na dalších službách? Jde mi čistě jen o to, jak to napsat syntakticky v .neon configu…
Nejsem u sebe na PC, ale mohlo by to být nějak takhle?

services:
    blueRepository: BlueRepository(@nette.database.default)
    redRepository: RedRepository(@nette.database.default)

    purpleFasade: PurpleFasade(@blueRepository, @redRepository)

Editoval PirateJack (2. 9. 2013 15:28)

Šaman
Člen | 2666
+
0
-

Tohle je téma na delší diskuzi přesahující samotný autowiring a DI a zasahující do návrhu architektury modelu. Já osobně ty inject metody používám i v té hlavní fasádě (tato hlavní modelová třída je u mě service locator a má tedy závislost na všech repository apod.)

V Nette 2.1 to lze udělat úplně stejně, jako v presenterech. Ve stable verzi to (určitě aspoň do 2.06, aktuálně nevím) pomocí autowiringu nešlo, ale ta fasáda se v configu dá nakonfigurovat ručně. (Ve třídě Model samozřejmě musí být metody setUserRepository() a injectFoo()) Pak to vypadalo takto:

services:
	userRepository: App\Model\UserRepository(@connection)
	foo: App\Foo
	model:
		class: App\Model\Model
		setup:
			- setUserRepository(@userRepository)
			- injectFoo(@foo) # když bude setter pojmenovaný inject, tak po přechodu na Nette 2.1 bude tento řádek zbytečný

Článek, na který odkazuje Filip znám a beru si ho k srdci, nicméně v určitých specifických případech používám injecty i mimo presentery. Důležité je vědět proč to dělám.

Ta širší diskuze, o které jsem mluvil na začátku, by se týkala toho, jak lépe navrhnout model, aby nevznikla potřeba rozšiřovat už tak nabobtnalý konstruktor při každém novém repository (a pak bez problémů použít constructor injection).

P.S. Pohrávám si s myšlenkou, že bych v tomto konkrétním případě nepoužíval inject metody, ale klasické settery a model skutečně konfiguroval výše popsaným způsobem v configu. Závislosti jsou pak lépe vidět a bylo by to zcela bez magie. DI porušená není a jediné, co hrozí, že někdo vytvoří new App\Model\Model a nepředá mu všechny potřebné závislosti. Pak by tento model samozřejmě nefungoval.


PirateJack napsal(a):

Super. Přečteno. Díky. :)
Inject metody v modelu jsou zlo, bo zavádějí nepodmíněné závislosti. (Chápu správně?)

Nevím, co myslíš tou nepodmíněnou závislostí. Ale obecně injectory (method injection) nejsou zlo, kvůli porušení závislostí (objekt se ke svým závislostem stále hlásí, DI porušená není). Problém je spíš v tom, že povinné závislosti by měly být v konstruktoru a pak nejde vytvořit nefunkční objekt. Když použiješ IDE s našeptáváním, tak při vytváření nové třídy ti ukáže parametry konstruktoru, ale určitě ti nedá zároveň i seznam setterů (injectorů), které musíš nastavit, aby objekt fungoval.

Tedy pokud repozitář potřebuje databázi a předáváš ji v konstruktoru, každý mu ji dodá.
Pokud na ni bude setter, každý druhý začátečník si tento repozitář vytvoří, nenastaví databázi a pak bude zjišťovat, proč mu nefunguje.


Edit: Ještě přihodím odkaz na dokumentaci, kapitolu konfigurace, kdybys to chtěl nastudovat podrobněji.

Editoval Šaman (2. 9. 2013 16:44)

PirateJack
Člen | 9
+
0
-

Souhlasím, někdy bych si rád popovídal o tom, jak navrhovat aplikaci tak aby jednotlivé fasady nebobtnaly, ale zpět k tématu.
Prosím Tě, máš definovanou servis třídu „model“, zajímá mě "@userRepository" je nějaká repository, ta je někde v konfigu zadefinovaná? Kde? Příjde mi, že se vzala odnikud… :/
Podobně "@foo"
Mohl bys prosím ten example rozvést? :)

Šaman
Člen | 2666
+
0
-

Doplněno, tyhle služby vytvářím úplně standardně, stejně jako ve tvém příkladu. Ukázka byla jen na konfiguraci té služby, která má povinné settery (injectory) v Nette 2.0×, kde se tyto metody nenastaví pomocí autowiringu. Ještě jsem ten původní příspěvek trochu rozvedl pod čarou, jen pro ujasnění toho „zla“. Ono to žádná pravidla neporušuje, jen existuje lepší řešení, které eliminuje možnost chybně vytvořeného objektu.


Ještě pro úplnost dodám, že všechny tři parametry v mém příkladu '(@cokoliv)' se dají vynechat, pokud daná metoda/konstruktor má definované jaké třídy očekává. Pak Nette automaticky dohledá správnou službu podle rozhraní. Viz dokumentace

Editoval Šaman (2. 9. 2013 17:00)