[výzkum] používáte Container::findByType() nebo findByTag()?
- David Grudl
- Nette Core | 8227
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 | 8227
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 | 8227
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 | 8227
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 | 8227
repli2dev napsal(a):
Používám(e)
findByType
v 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 | 248
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 | 8227
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 | 1274
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 | 1245
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)