createComponent*: injectování továrničky přímo do metody
- David Matějka
- Moderator | 6445
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 – koukněte níže a nainstalujte si
balíček od hosiplana :)
(je to v hlavnim Presenteru, s trochou snahy to jde narvat i do předka
všech komponent (Control))
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)
- vvoody
- Člen | 910
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
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
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
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? :-)
- David Matějka
- Moderator | 6445
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)
- David Matějka
- Moderator | 6445
@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
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
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
vytvoren composer balíček
matej21/nette-autowire-component-factories
a trait
matej21\AutowireComponentFactories
takze staci do base presenteru
use \matej21\AutowireComponentFactories;
- David Matějka
- Moderator | 6445
funkcionalita byla integrována do kdyby/autowired. více v dokumentaci
Editoval matej21 (11. 5. 2013 17:24)