createComponent*: injectování továrničky přímo do metody

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Matějka
Moderator | 6445
+
0
-

Ahoj,
DI factories jsou dobrá věc, ale vyžadují nějak dostat factory do createComponent* metody.
inject* jsou pěkný, ale je to moc psaní, @autowire je ještě hezčí (rozuměj jednodušší), ale pořád je to moc psaní :)
trochu jsem si upravil createComponent metodu, aby to ještě usnadnila, viz https://gist.github.com/matej21/5079124
(je to v hlavnim Presenteru, s trochou snahy to jde narvat i do předka všech komponent (Control))
 – koukněte níže a nainstalujte si balíček od hosiplana :)

teď si můžu dovolit tenhle nejhezčí (rozuměj nejjednodušší) zápis:

public function createComponentFoo(FooFactory $factory)
{
	$foo = $factory->create();
	return $foo;
}

a je to asi méně black magic než u @autowire :)

createComponent* metody je nutno mít jako public, ale pokud máte nějaké existující definovaný jako protected, tak se zavolají starym způsobem. EDIT: v upravené verzi uz nemusi byt metoda public

také můžete jako první parametr vyžadovat název komponenty (ten parametr, který se tam posílá teď)

public function createComponentFoo($name, FooFactory $factory)

kód zde – viz níže

UPDATE:
můžete použít composer balíček matej21/nette-autowire-component-factories, v kodu potom do BasePresenteru použít trait use \matej21\AutowireComponentFactories;

UPDATE2:

tato funkcionalita byla integrována do kdyby/autowired od Filipa Procházky. více v dokumentaci

Editoval matej21 (11. 5. 2013 17:33)

Majkl578
Moderator | 1364
+
0
-

To se mi nelíbí, vyžaduje to prezenci DI\Containeru, jehož se snažíme zbavit. :)

vvoody
Člen | 910
+
0
-

Mne sa to nepáči lebo niesu jasne viditeľné závislosti presenteru, tak ako keď je vidno property s továrňou. Radšej zachovaj property s továrňou a pridaj jej nejakú anotáciu ktorú budeš hľadať v createComponent metóde. Takto budeš mať oddelené injectovanie továrničky od vytvárania komponenty, potom bude môcť každý podla vlastného uváženia použiť buď inject metódy alebo lazy-autowire

David Matějka
Moderator | 6445
+
0
-

ano, je tam zavislost na DIC, ale na nem jsou zavisli treba i @autowire anotace

@vvody: j, asi jsem tam tu zavislost mel definovat jasnejc a nespolehat se na Nette\Application\UI\Presenter::$context, ale klidne si tam muzes dopsat

public function injectContainer(Nette\DI\Container)

at to mas koser :)

Filip Procházka
Moderator | 4668
+
0
-

To použití je fakt super… ale skřípu u toho zuby, stejně jako u @autowire :-/ Začínám si říkal, že u presenterů bych si (sobě) dovolil ještě větší ústupky (třeba tohle)…

Udělej to jako rozšíření, podobně jako jsem to udělal já. Přímo v Nette by to rozhodně být nemělo.

A nesouhlasím s tím, že metoda musí být public ;)

sifik
Člen | 27
+
0
-

matej21 napsal(a):
(je to v hlavnim Presenteru, s trochou snahy to jde narvat i do předka všech komponent (Control))

Tohle by mě docela zajímalo, jak to udělat? Nevidím jedinou možnost, než zvlášť přepsat metodu createComponent pro presenter a zvlášť pro control… Nebo dokážeš udělat společného předka, aby nemusel ten samý kód na dvou místech? :-)

Filip Procházka
Moderator | 4668
+
0
-

Ano, dokáže – udělá z toho traitu, jak jsem mu radil ;)

David Matějka
Moderator | 6445
+
0
-

j bud to narves do obou obojiho, nebo pokud mas PHP 5.4, tak muzes pouzit traity

ale to uz by skripali zuby i ti, co uz je nemaji :) musel byt upravit createComponent jeste v tomhle stylu a do toho spolecneho predka komponent (zdedeny Nette\Application\UI\Control) narvat public function injectContext(Nette\DI\Container $context)

enumag
Člen | 2118
+
0
-

@matej21: U komponent je lepší řešit závislosti konstruktor. To mé řešení na které odkazuješ už ani sám nepoužívám. ;-)

Ta traita by ale byla fajn, ten autowiring továren je i s tou traitou od @hosiplana trošku ukecaný.

David Matějka
Moderator | 6445
+
0
-

@enumag: j je to lepsi pres konstruktor, ale to by kazda komponenta, ktera dedi od toho Controlu musela mit v konstruktoru Container, pokud by vyzadovala i nejake svoje dalsi zavislosti

public function __construct(Container $context, DalsiZavislot $foo)
{
	parent::__construct($context);
}

coz by bylo psani navic a nachylny k chybam. To tam fakt radsi dam ten nehezkej injectContext :)

jinak trait a composer balicek vytvorim snad dneska, jestli mi na to zbyde cas :)… ouch, House of Cards ma titulky na 80%.. takze asi budu mit vecer o 45 minut mene casu :D

Filip Procházka
Moderator | 4668
+
0
-

Těm co to ještě neudělali, bych doporučil důkladně si pročíst tento příspěvek.

Filip Procházka
Moderator | 4668
+
0
-

Co něco takového?

trait AutowireComponentFactories
{
	/** @var \Nette\DI\Container */
	private $serviceLocator;

	/** @return \Nette\DI\Container */
	protected function getServiceLocator()
	{
		if ($this->serviceLocator === NULL) {
			return $this->getPresenter()->getContext(); // fallback
		}

		return $this->serviceLocator;
	}

	/** @internal */
	public function injectServiceLocator(Nette\DI\Container $sl)
	{
		$this->serviceLocator = $sl;
	}

	public function createComponent($name)
	{
		$sl = $this->getServiceLocator();
		// ..
	}

}

Kdo bude chtít, tak si metodu přetíží a bude si předávat DI Container například přes konstruktor a zároveň poskytneš funkční výchozí řešení s minimem psaní.

inject*() nad komponentami nemám rád, ale tohle je taková zlatá střední…


A napadla mě ještě jedna věc. Možná by to nějak zajistit, aby šla doplnit pouze továrnička na komponentu, jinak to budou lidi znásilňovat, aby si tam předali konkrétní závislosti a vytvářeli komponentu pomocí new. No a nebo je to možná jedno.

David Matějka
Moderator | 6445
+
0
-

vytvoren composer balíček matej21/nette-autowire-component-factories a trait matej21\AutowireComponentFactories

takze staci do base presenteru use \matej21\AutowireComponentFactories;

hrach
Člen | 1838
+
0
-

uzasny :D asi to brzy zacnu pouzivat :)

David Matějka
Moderator | 6445
+
0
-

funkcionalita byla integrována do kdyby/autowired. více v dokumentaci

Editoval matej21 (11. 5. 2013 17:24)