[výzkum] používáte Container::findByType() nebo findByTag()?

- David Grudl
- Nette Core | 8285
Nettí DI kontejnery sebou nesou poměrně velká metadata, která
zajišťují funkčnost Container::findByType() a
findByTag().
Rád bych metadata zmenšil, protože se domnívám, že se v praxi tyto
metody tolik nepoužívají. Podotýkám, že se bavím o metodách přímo
kontejneru, nikoliv ContainerBuilder.
Pokud tyto metody používáte, napište mi prosím k čemu konkrétnímu.
(Příklad: nette/application 2.4 si pomocí tagu nette.presenter vytahovala názvy služeb s presentery.)

- dada-amater
- Bronze Partner | 52
Různá rozšíření pouzivaji findByTag. Z hlavy mě napadá
třeba starší Kdyby/Events. Ten use case mi přijde celkem
praktický.

- David Grudl
- Nette Core | 8285
LukasV napsal(a):
Ne myšlena i metoda
getByType()nebo jen ty dvě zmíněné?
Ne, ta je z celého kontejneru nejdůležitější :-)

- David Grudl
- Nette Core | 8285
dada-amater napsal(a):
Různá rozšíření pouzivaji
findByTag.
Bylo by schůdné řešení, kdyby extension nově oznámila, které tagy chce exportovat? Třeba pomocí:
$builder->addExportedTag('xxxx');

- David Grudl
- Nette Core | 8285
dada-amater napsal(a):
Z hlavy mě napadá třeba starší
Kdyby/Events. Ten use case mi přijde celkem praktický.
Když koukám na kód Kdyby/Events, vidím tam volat findByTag() jen na builderu… Nad kontejnerem to vidím jen v Kdyby/RabbitMq.

- David Grudl
- Nette Core | 8285
repli2dev napsal(a):
Používám(e)
findByTypev DI extensionech, v testech a případě že používám třeba jen Nette DI a chci v nějaké místě vytahovat konkrétní závislosti (protože v daném místě to nejde řešit jinak).
Mohl bys mi to popsat co nejkonkrétněji prosím?

- Milo
- Nette Core | 1283
Občas jsem použil findByType(). Zejména v jedné modulární
aplikaci. Jednotlivé moduly měly vlastní config.neon soubor a
v něm přidávaly služby do kontejneru. Jádro aplikace nebo nějaké obecné
moduly si potom v DI kontejneru hledaly podle interfacu. Například
bin/cli-admin hledal App\Cli\IAdminModule anebo
daemon, hlídající alarmy, hledal
App\Monitoring\IAlarmProvider.
Už ani nevím, proč jsem to v DI kontejneru hledal v runtime. V compile
time by to šlo taky. A teď v novém DI bych si to asi nechal injektovat
přes type().

- 2bfree
- Člen | 252
Ale v podstatě to nejdůležitější vypadá takto:
<?php
/**
* Service alias setup helper
*
* @param string $type
* @param string $alias
* @return bool
* @throws ServiceCreationException
*/
protected function setupServiceAlias(string $type, string $alias): bool
{
$builder = $this->getContainerBuilder();
$services = $builder->findByType($type);
$serviceName = key($services);
$isServiceAliasAdded = false;
if ($serviceName !== null) {
if (next($services) !== false) {
throw new ServiceCreationException(sprintf('Multiple services of type "%s" found', $type));
}
$builder->addAlias($this->prefix($alias), $serviceName);
$isServiceAliasAdded = true;
}
return $isServiceAliasAdded;
}
?>

- Kacer_Bob
- Člen | 7
Metodu findByType() používám k nalezení služby
implementující určitý interface, ale nepotřebuji, aby mi DI kontejner
vyráběl instance všech těch služeb.
V podstatě bod 2 zde: https://github.com/…/di/pull/178#…
Taky používám findByType() v kombinaci s
isCreated(), protože neexistuje ekvivalentní metoda k
isCreated(), která by měla jako parametr třídu služby. Proto
přes findByType() zjistím název služby (je registrovaná jako
anonymní) a pak volám isCreated().

- David Grudl
- Nette Core | 8285
Děcka ještě pro jistotu jednou, řeč není o builderu a compiler
extensions, ale o tom, co děláte s $container.

- Marek Bartoš
- Nette Blogger | 1313
V aplikaci to používáme pro lazyloading factories pro loginy skrze sociální sítě. Přidávají se dynamicky a není možné tak injectovat konkrétní factories.
Imho ale vůbec není problém to nahradit, kupříkladu
v contributte/event-dispatcher si v LazyEventDispacher
předáváme jen názvy služeb a získáváme je přes
getService().
U findByTag() nevím – tagy používám jen pro hromadnou
konfiguraci služeb, nikdy pro jejich získávání. Přijde mi to jako
zastaralé a nyní už absolutně zbytečné řešení, když se dají nahradit
skrze interface a názvy služeb v compile-time.
Jediný problém, co mě napadá je pořadí extensions pracujících se stejným type – v run-time už máš služby ze všech extensions, v compile-time jen z extensions, které jsou zaregistrované dřív.
Jinak zmenšení metadat je super nápad. V kontajneru o 10k řádků nám
dělají 3k jen metadata, které php nemůže nijak optimalizovat.
I parametry mají nějakých 100 řádků, které jsou tam úplně zbytečně,
protože se jich většina používá jen při kompilaci.

- Felix
- Nette Core | 1271
Projel jsem skoro vsechny kody contributte / nettrine a apitte:
- findByTag (7x) – volany jenom v CompilerExtension
- findByType (45x) – 44× volany jenom v CompilerExtension
Jediny, kde je pouzito findByType v runtime je u nettrine/orm u ManagerRegistry.
Coz by slo nejspis predelat. :-)
Realne na projektu to moc nepouzivame, jenom vyjimecne. Kdyz se nadtim
zamyslim, tak by slo vsechno napsat pres findByType, ale u
findByTag vidim pohodlnost v tom, ze mam napr. 5 typu sluzeb
(dost casto nejaky lazy vytvareni komponent) co chci z DI vytahnout. A vsem
tem sluzbam dam tag a v kodu si pak rozhodnu co s tim chci delat. Jasne, slo
by to zavolat 5× s findByType, ale 1× findByTag je
v tomhle pohodlnejsi.
Jinak jak pise @Mabar.

- xificurk
- Člen | 121
Container::findByType() používáme na několika místech
v testech pro:
- Inspekci služeb registrovaných ve vygenerovaném kontejneru – kontrolujeme např. že jsou všechny služby určitého typu opravdu zaregistrovány v kontejneru
- Nahrazení originální (anonymní) služby nějakým mockem pro konkrétní testcase.
Tagy obecně v runtime nepoužíváme.
Editoval xificurk (5. 3. 2019 20:40)

- Honza Kuchař
- Člen | 1662
Používám oboje. Přes tagy si značím veřejné služby, které si potom vytahuji a registruji v druhého kontejneru. Šlo by řešit i staticky přes kontejner, pokud bude možné injektovat všechny služby daného typu do array/variadického parametru.
getByType a findByType používám hlavně
v testech. Druhé použití pro mě je, když mám dva kontejnery. Vnější
registrovaný jako službu v tom vnitřním a potřebuji z vnějšího podle
interface vytáhnout služby.
Příklady:
findByTag() – Při více kontejnerech v sobě – Nette
DI scope, kde se z vnitřního kontejneru musí po kompilaci registrovat
služby v tom vnějším.
findByType() – v commandu, který vytahuje všechny process
managery:
protected function execute(InputInterface $input, OutputInterface $output): int
{
foreach ($this->container->findByType(ProcessManagerType::class) as $serviceName) {
$type = $this->container->getService($serviceName);
\assert($type instanceof ProcessManagerType);
$output->writeln("Starting process manager <comment>$serviceName</comment>");
$this->runProcessManager($type, $output);
$output->writeln("<info>Process manager</info> <comment>$serviceName</comment> <info>finished - no more events to process</info>.\n");
}
getByType() – při vytahování služby podle interface
z vnějšího kontejneru
services:
clock:
class: Brick\DateTime\Clock
create: @outerContainer::getByType(Brick\DateTime\Clock)
Editoval Honza Kuchař (5. 3. 2019 22:10)