Vícenásobné použití formuláře: dědičnost nebo továrna?
- David Grudl
- Nette Core | 8254
Pokud potřebujeme v programu opakovaně vytvořit & nakonfigurovat určitý objekt, použijeme k tomu účelu továrničku (factory). To je asi zřejmé.
Továrničku obvykle implementujeme jako samostatnou třídu. Implementovat ji tak, že vytvoříme potomka vytvářené třídy a do něj ji přidáme, by bylo porušením Single Responsibility Principe. Samozřejmě z praktických důvodů lze jakékoliv pravidlo porušit, ale pokud praktické důvody nejsou, pišme čistější kód.
A pokud tedy potřebujeme na webu vytvořit opakovaně stejný formulář, je správnější si na to vytvořit továrničku, nikoliv (zne|vy)užívat konstruktor.
Místo řešení uvedeném na https://pla.nette.org/…ho-formulare nebo https://forum.nette.org/…a-onvalidate#… bych doporučoval spíš následující:
A poté si do presenteru předáme službu CreateOrEditUserFormFactory…
…čímž se vyhneme používání contextu:
- Filip Procházka
- Moderator | 4668
Tak udělej stable tag, kde se to bude dát použít a já to začnu radit lidem ;)
- David Grudl
- Nette Core | 8254
Podstatný je rozdíl mezi
CreateOrEditUserForm extends Form
versus
CreateOrEditUserFormFactory
.
Pokud jde o předání služby do presenteru, ve 2.0.4 se použije místo
__construct
metoda setContext
(případe
v konstruktoru předá Nette\DI\Container), což je detail.
- Filip Procházka
- Moderator | 4668
setContext()
je nepoužitelný
Co se týče továrniček. Přístup který ukazuješ je super, ale moc nekamarádí s DIC factories. Pokud tedy chceme jít touhle cestou, bude potřeba se jich zbavit. Ostatně, už jsem vzdal snahy o jejich použitelnost.
Editoval HosipLan (22. 8. 2012 18:03)
- David Grudl
- Nette Core | 8254
Proč by byl nepoužitelný? Je IMHO lépe použitelný než __construct, protože v případě chyby kvůli dědičnosti vyhodí strict error. A s DIC factories se to nijak netluče.
- Filip Procházka
- Moderator | 4668
No netluče. Ale na co máme DIC factories, když jsou „nepoužitelné“?
- Elijen
- Člen | 171
22 napsal(a):
- + 1 @Hosiplan zrovna dneska jsme narazili při debatě na to, jak předat továrnu někam dál v rámci DIC? Respektive jak se vyhnout přístupu k továrně volaním
$this->context
, tedy jak ji injectnout dopresenteru
?
No přece úplně stejně jako jakoukoliv jinou závislost.
@HosipLan: Proč by DIC factories měli být nepoužitelné? A není to OT? :)
- thunderbuff
- Člen | 164
22 napsal(a):
@Elijen: Můžeš mi ukázat, jak se v presenteru dostaneš k factory nadefinované v neonu, aniž by ses dotknul $this->context?
neřeší se to zde?
https://phpfashion.com/…-presenterum
- pawouk
- Člen | 172
50 formulářů v presenteru je dost málo pravděpodobné že budeš mít :-) Ale pokud jich opravdu budeš mít 50 a chceš dělat věci v souladu s DI tak ano. Mě teda osobně strašně vadí že v configu nejde udělat callback/anonymni funkce. Tak jsem si to dodělal a používám to nějak takto:
Config:
To vytvoří callback a ten mohu předávat smostatně bez contextu. Už jsem na to narážel asi před půl rokem a odpověď davida byla že to bude v příštím vydání, škoda že to tam stále není. Nebo se pletu?
Davidovo řešení se mi teda vůbec nelíbí, podle mě zbytečné psaní kod, zbytečná třída…
- mildabre
- Člen | 62
David Grudl napsal(a):
Podstatný je rozdíl mezi
CreateOrEditUserForm extends Form
versusCreateOrEditUserFormFactory
.Pokud jde o předání služby do presenteru, ve 2.0.4 se použije místo
__construct
metodasetContext
(případe v konstruktoru předá Nette\DI\Container), což je detail.
Díky Davide za tenhle článeček. První formulář jako komponentu jsem vytvořil takto:
Přitom je jasné, že třída emloyeeForm je stejná jako její předek, takže to dědění je zde „zneužité“ pro jiné účely. Když k tomu člověk přijde poprvé, tak ho asi vždy napadne dědění, factory třída je takový ten Nette way, člověk si na ty Nette postupy musí zvyknout.
- doublemcz
- Člen | 15
Vytvářím formuláře přesným postupem nahoře. Oddědim od Form, vytvářit přes factory nadefinovaného v neonu.
Každopádně středně velká aplikace bude mít desítky formulářů (zatím mají všechny stejné nastavení) a neon roste a roste. Nejde vytvořit nějakou jednu factory classu, která by to řešila a já bych v presenteru pouze určil jméno?
Takhle tam bude za chvíli stovky řádků jenom na vytváření formulářů :-)
Editoval doublemcz (16. 7. 2013 9:34)
- pseudonym
- Člen | 57
David Grudl napsal(a):
Pokud potřebujeme v programu opakovaně vytvořit & nakonfigurovat určitý objekt, použijeme k tomu účelu továrničku (factory). To je asi zřejmé.
Továrničku obvykle implementujeme jako samostatnou třídu. Implementovat ji tak, že vytvoříme potomka vytvářené třídy a do něj ji přidáme, by bylo porušením Single Responsibility Principe. Samozřejmě z praktických důvodů lze jakékoliv pravidlo porušit, ale pokud praktické důvody nejsou, pišme čistější kód.
A pokud tedy potřebujeme na webu vytvořit opakovaně stejný formulář, je správnější si na to vytvořit továrničku, nikoliv (zne|vy)užívat konstruktor.
Místo řešení uvedeném na https://pla.nette.org/…ho-formulare nebo https://forum.nette.org/…a-onvalidate#… bych doporučoval spíš následující:
A poté si do presenteru předáme službu CreateOrEditUserFormFactory…
…čímž se vyhneme používání contextu:
Vyzera to presne ako to co potrebujem, len by ma zaujimalo, ako v metode
process()
zavolam redirect()
? Musim si do tejto
tovarnicky nejako cez konstruktor poslat Presenter? Alebo sa to da aj
nejako inak?
- xificurk
- Člen | 121
pseudonym napsal(a):
Vyzera to presne ako to co potrebujem, len by ma zaujimalo, ako v metode
process()
zavolamredirect()
? Musim si do tejto tovarnicky nejako cez konstruktor poslat Presenter? Alebo sa to da aj nejako inak?
$form->getPresenter()
, druhou možností je při vytváření
formuláře v createComponentCreateOrEditUserForm
na něj navěsit
další callback na onSuccess (nebo co potřebuješ).
- snake.aas
- Člen | 25
xificurk napsal(a):
pseudonym napsal(a):
Vyzera to presne ako to co potrebujem, len by ma zaujimalo, ako v metode
process()
zavolamredirect()
? Musim si do tejto tovarnicky nejako cez konstruktor poslat Presenter? Alebo sa to da aj nejako inak?
$form->getPresenter()
, druhou možností je při vytváření formuláře vcreateComponentCreateOrEditUserForm
na něj navěsit další callback na onSuccess (nebo co potřebuješ).
Pokud ale máš více callbacků, ta pozor na přesměrování při chybě.
Pokud se v prvním callbacku zneplatní formulář, druhý onSuccess se stejně
provede (a tedy přesměruje)
Jak jsem psal tady