Autowiring ve fasade class
- PirateJack
- Člen | 9
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
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
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
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
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
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)