metoda inject() v presenterFactory

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

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…

hrach
Člen | 1838
+
0
-

rename metody je na 5 minut, ne?

Editoval hrach (19. 9. 2012 9:43)

pawouk
Člen | 172
+
0
-

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
+
0
-

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
+
0
-
  1. 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?

  1. 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
+
0
-

pawouk napsal(a):

  1. 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… :-)

pawouk
Člen | 172
+
0
-

OK, to jen na upřeněnou :-)

David Grudl
Nette Core | 8212
+
0
-

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
+
0
-

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.