metoda inject() v presenterFactory
- pawouk
- Člen | 172
Tak jsem si právě stáhnul nové nette a hned na mě vypadla chyba. Ta je bohužel způsobená trochu historii vývoje mé aplikace. V naší firmě už dlouho používáme metodu inject($dependences) pro předání závislostí. Dependences je container závislostí (pro každou třídu jiný). Jenže bohužel novinkou v je v presenterFactory toto:
foreach (array_reverse(get_class_methods($presenter)) as $method) {
if (substr($method, 0, 6) === 'inject') {
$this->container->callMethod(array($presenter, $method));
}
}
Díky čemuž inject tak jak jsme ho používali do ted nemůže fungovat. Nebylo by prosím možné metodu zmenit tak aby se volala pouze pokud má za inject nějaký název? Tedy:
foreach (array_reverse(get_class_methods($presenter)) as $method) {
if (substr($method, 0, 6) === 'inject' && strlen($method) > 6) {
$this->container->callMethod(array($presenter, $method));
}
}
Myslím že nejsem sám kdo používá už nějaký pátek metodu inject a překopávat celý projekt se mi tedy moc nechce. Mimochodem by mě zajímalo jaký směrem se vyvíjí DI v nette. Na davidovém blogu bylo spoustu návrhů, ale který z nich vede zatím nevím. Rád bych se ktomu také vyjadřil a zdělil sve zkušenosti s použitím různých variant…
- pawouk
- Člen | 172
No to asi jo, ale přijde mi že nette to chce využívat práve ve spojení s názvem co chce injektovat (service nikoliv kontainer). Alespoň tak odhaduji dle substr($method, 0, 6) === ‚inject‘ tak mi přijde že inject sam o sobě by takto neměl být používáno na injektování z configu dle typu.
- Patrik Votoček
- Člen | 2221
Nette umí jak inject tak injectFoo. A je to z toho
důvodu aby se mohlo s dopřednou kompatabilitou přejemnovat stávající
metody setContext
na inject
(bez dalšího
zásahu).
Ve stávajících aplikacích se totiž zhlediska DI vyskytoval takovýto kód:
public function setContext(\Nette\DI\Container $context)
{
$this->model = $context->model;
$this->someOther = $context->someOther;
}
Protože pokud tvůj BasePresenter má nějaké závislosti a FooPresenter přidává další tak to jaksi nejde jinak.
Takže nyní jde s ohledem na dopřednou kompatabilitu pouze přejmenovat
setContext
na inject
. Při přidávání nových
závislostí se už pochopitelně použije výřečnější varianta
injectFoo
.
- pawouk
- Člen | 172
- Pokud má BasePresenter nějaké závislosti a FooPresenter nějaké přidává přišlo by mi mnohem logičtější toto:
public function setContext(\Nette\DI\Container $context)
{
$this->someOther = $context->someOther;
parent::setContext($context);
}
// a v předkovi:
public function setContext(\Nette\DI\Container $context)
{
$this->model = $context->model;
parent::setContext($context);
}
Nebo co když je BasePresenter zavislí na modelu který je private?
- Mě se to injektování metodami stejně moc nelíbí, je to strašného kodu navíc. Proč neobstálo property injection navrhované v https://phpfashion.com/cs/ s unsetnutím v konstruktoru, to mě přišlo dobrý :-)
- Patrik Votoček
- Člen | 2221
pawouk napsal(a):
- Pokud má BasePresenter nějaké závislosti a FooPresenter nějaké přidává přišlo by mi mnohem logičtější toto:
O tom já se přece nepřu… přesně tak jsem to taky používal… :-)
- David Grudl
- Nette Core | 8228
pawouk napsal(a):
Tak jsem si právě stáhnul nové nette a hned na mě vypadla chyba. Ta je bohužel způsobená trochu historii vývoje mé aplikace. V naší firmě už dlouho používáme metodu inject($dependences) pro předání závislostí.
Je velmi nepříjemné, když se ve větvi 2.0.x objeví nekompatibilita, v případě této úpravy byly důvody skutečně opodstatněné. Nicméně inject řeší přesně to, k čemu jste inject používali. Mělo by to tedy fungovat i nyní. Jak jste vlastně svůj inject volali?
- pawouk
- Člen | 172
No jak jinak než v presenterFactory:
class PresenterFactory extends \Nette\Application\PresenterFactory {
private $context;
public function __construct($baseDir, Nette\DI\Container $context) {
$this->context = $context;
parent::__construct($baseDir, $context);
}
public function createPresenter($name) {
$presenter = parent::createPresenter($name);
$dependences = $this->context->diContainer->get($presenter);
$presenter->inject($dependences);
return $presenter;
}
}
Máme vlastní diContainer který dostane nějakou třídu, Kromě toho máme vlastní sekci v configu dependences (pomoci Config\Extensions), která vypada takto:
dependences:
NejakaTrida:
translator: @translator
editFormFactory:
callback:
new: EditForm
To me prislo lepsi protože je jasné dané jaká třída má jaké zavislosti a navíc umí callbacky.
S teto sekce se ziskaji zavislosti. Pak se zeptame na predka get_parent_class($trida) a to same se udela na predka. Tim se poskladaji všechny potřebné závislosti. To vše se strčí do objektu Dependences a ten se pak vrátí. Do metody inject tedy vždy přijde objekt typu Dependences. Nevim jak to ted obejít.