Nekonzistentní Presenter při vytvoření nového objektu
- Ondřej Mirtes
- Člen | 1536
Use case: Jsem v nějakém CLI skriptu a potřebuji generovat odkazy. Např.
rozesílám e-maily a potřebuji se z nich odkázat na vlastní web. Co proto
musím udělat kromě samozřejmého naplnění proměnných
$_SERVER['HTTP_HOST']
apod. o které se normálně stará
Apache?
Za účelem generování si vytvořím nový presenter:
$presenter = new HomepagePresenter();
Člověk by si myslel, že nyní může na presenteru volat metodu
link()
a dostane, co očekává. Splnil všechny závislosti,
které mu rozhraní konstruktoru předepsalo.
Ale omyl! Vysypaly se na mě errory a noticky a já se jal zkoumat zdrojáky.
Přišel jsem na to, že Presenter je až do zavolání metody
run()
ve strašně nekonzistentním stavu. PresenterRequest by měl
být přijímán už v konstruktoru, protože bez něj objekt Presenteru
nedává smysl. Zároveň si myslím, že Presenter není zrecyklovatelný pro
více běhů nad různými requesty, takže by to skutečně dávalo smysl.
Jsou to trochu laboratorní podmínky, ale v těchto momentech vývojář zjišťuje, že mu Nette vlastně nepomáhá, ale překáží.
Těchto míst je v Nette víc (např. RobotLoader by měl CacheStorage přijímat v konstruktoru a ne setterem) a pro zavedení opravdové DI je potřeba je všechny odstranit. Zkrátka pokud se mi vede vytvořit nový objekt dané třídy, už by mi měl dovolit s ním dělat cokoli, aniž bych se musel vrtat ve zdrojácích a zjišťovat, proč to nefunguje. To je DI.
- David Grudl
- Nette Core | 8218
Ondřej Mirtes napsal(a):
PresenterRequest by měl být přijímán už v konstruktoru, protože bez něj objekt Presenteru nedává smysl. Zároveň si myslím, že Presenter není zrecyklovatelný pro více běhů nad různými requesty, takže by to skutečně dávalo smysl.
Je to tak, pošleš patch?
Těchto míst je v Nette víc (např. RobotLoader by měl CacheStorage přijímat v konstruktoru a ne setterem) a
Stejně tak by měl přijímat seznam adresářů, co když zapomenu zavolat addDirectory()? Tenhle argument prostě neobstojí. Jelikož se instance stejně vytváří jen v Configuration, neobstojí ani můj argument s lepší čitelností kódu, takže klidně pošli patch.
pro zavedení opravdové DI je potřeba je všechny odstranit.
Jaké jsou další případy?
- Ondřej Mirtes
- Člen | 1536
Pošlu patche :)
U téhle situace jsem si jistý v těchto dvou případech, ale je možné, že se to děje ještě jinde, kde jsem na to nenarazil.
- Ondřej Mirtes
- Člen | 1536
Uvědomil jsem si, že s rozhraním IPresenter nic špatně není, takže to
spíš budu muset směřovat tím, že opravím ten stav Presenteru před
run()
, pokud to nějak půjde.
- Honza Marek
- Člen | 1664
Ondřeji, neposílej patch, vymluv se na lenost! :)
Vždyť pak nepůjde jednoduše udělat presenter factory ve stylu
class PresenterFactory implements IPresenterFactory
{
private $container;
public function __construct($container)
{
$this->container = $container;
}
public function createPresenter($name)
{
return $this->container->getService($name);
}
}