Závislosti s proměnným názvem

medhi
Generous Backer | 255
+
0
-

Ahoj, používám takový pattern, kdy v presenteru dostanu zvenčí název třídy a tu si pak načtu jako službu pomocí $this->context->getByType(...); a spustím na ní metodu run(), tedy nějak takto:

$commandClassName =  "App\\ApiModule\\Commands\\" . ucfirst($commandName) . "Command";
if (empty($commandName) || ! class_exists($commandClassName)) {
	$this->terminate();
}
$command = $this->context->getByType($commandClassName);
$command->run(...);

Lze toto nějak vyřešit bez použití $this->context, které nyní už hází deprecated?

Díky

Marek Bartoš
Nette Blogger | 1260
+
0
-

Obecný postup je vytvořit si extension, zaregistrovat si v ní službu a do té služby předat mapu klíčů podle kterých hledáš službu a název služby. Do klíče si dáš ‚type‘ z definice služby, do hodnoty ‚name‘ z definice služby. Služba pak z containeru získá tvůj command pomocí názvu služby z toho commandu.

Používám tenhle pattern na lazy loading kolekcí často, tak jsem si udělal type-safe helper https://github.com/…cs/README.md#…
Jednoduchá implementace je v ukázce, případně tady: https://github.com/…yManager.php
V extension je pak registrace rozdělená do loadConfiguration(), kde se registruje „manager“ a do beforeCompile(), kde se do manageru přidává mapa služeb. Pokud nechceš manager konfigurovat v neonu nebo jiných extensions, tak ti stačí obojí udělat naráz v beforeCompile() https://github.com/…xtension.php#…

Fajn na tom je, že všechny služby najdeš už při kompilaci a nemusíš do containeru ukládat metadata pro getByType()

Editoval Marek Bartoš (18. 5. 2022 11:07)

medhi
Generous Backer | 255
+
0
-

Marek Bartoš napsal(a):

Obecný postup je vytvořit si extension, zaregistrovat si v ní službu a do té služby předat mapu klíčů podle kterých hledáš službu a název služby. Do klíče si dáš ‚type‘ z definice služby, do hodnoty ‚name‘ z definice služby. Služba pak z containeru získá tvůj command pomocí názvu služby z toho commandu.

Používám tenhle pattern na lazy loading kolekcí často, tak jsem si udělal type-safe helper https://github.com/…cs/README.md#…
Jednoduchá implementace je v ukázce, případně tady: https://github.com/…yManager.php
V extension je pak registrace rozdělená do loadConfiguration(), kde se registruje „manager“ a do beforeCompile(), kde se do manageru přidává mapa služeb. Pokud nechceš manager konfigurovat v neonu nebo jiných extensions, tak ti stačí obojí udělat naráz v beforeCompile() https://github.com/…xtension.php#…

Fajn na tom je, že všechny služby najdeš už při kompilaci a nemusíš do containeru ukládat metadata pro getByType()

Díky, to už je pro mě dost kanón na vrabce (čti, je to na mě moc složitý).

Zatím po delším zkoumání jsem skončil u předání všech závislostí přes jednu inject* metodu, uložení jich do privátních proměnných a potom je volám jako $this->$className.

Pokud těch tříd je do 10 kusů, tak to ještě není tak nepřehledný.

medhi
Generous Backer | 255
+
0
-

Mimochodem, přesně pro tyhle případy nechápu, proč už není kontejner kdekoli stále k dispozici. Tady se z jednoduchého pochopitelného a čitelného kódu stává něco hodně ošklivého :( Princip a užitečnost DI chápu, ale asi by to nemělo být za každou cenu. Jenom můj hodně laický pohled.

Marek Bartoš
Nette Blogger | 1260
+
0
-

Tak můžeš to obejít tak, že si Container injectneš do třídy sám.

Já používám komplikované řešení, protože se celé schová do jedné třídy (+extension, když chceš služby zadrátovat automaticky), nepotřebuje jinak zbytečná data ve vygenerovaném kontejneru, o všech chybách se dozvím už při kompilaci kontejneru, je to snadno přetížitelné v konfigu a lze napsat i propojení s phpstanem a zjistit, zda každá z těch v runtime získávaných služeb existuje.

medhi
Generous Backer | 255
+
0
-

Marek Bartoš napsal(a):

Tak můžeš to obejít tak, že si Container injectneš do třídy sám.

Já používám komplikované řešení, protože se celé schová do jedné třídy (+extension, když chceš služby zadrátovat automaticky), nepotřebuje jinak zbytečná data ve vygenerovaném kontejneru, o všech chybách se dozvím už při kompilaci kontejneru, je to snadno přetížitelné v konfigu a lze napsat i propojení s phpstanem a zjistit, zda každá z těch v runtime získávaných služeb existuje.

Snad se jednou dopracuju i tomu, věřím, že to mám spoustu dalších výhod. Zatím zkusím to injectnutí Containeru. Poradíš jak na to? A je to velká prasárna? Předpokládám menší než $this->getContext().

Díky

David Grudl
Nette Core | 8218
+
+2
-
function inject(Nette\DI\Container $container)
{
}
Marek Bartoš
Nette Blogger | 1260
+
0
-

Jak píše David a je to úplně totéž co $this->getContext(). Jen už si o Container musíš říct sám, namísto toho aby byla závislost přímo v Nette.

medhi
Generous Backer | 255
+
+2
-

David Grudl napsal(a):

function inject(Nette\DI\Container $container)
{
}

Krásný, BTW netušil jsem, že inject() jde použít i anonymně 👍