Proč vyhazuje $container->getByType(‚Nette\Application\PresenterFactory‘); error?
- joseff
- Člen | 233
Zdravím, nechápu, že když napíšu do bootstrapu:
$container->getByType('Nette\Application\PresenterFactory');
Tak to vypíše chybu:
Nette\DI\MissingServiceException
Service of type Nette\Application\PresenterFactory not found.
Ale když si dumpnu:
dump($container->getByType('Nette\Application\IPresenterFactory'));
Tak mi to dumpne „Nette\Application\PresenterFactory“ Může mi tohle někdo vysvětlit?
- David Matějka
- Moderator | 6445
Je to vlastnost nette/di, ze pokud je u service definition nastaveno
class
i factory
, tak se uvedena class pouzije jako typ
te sluzby a nette/di se nesnazi zjistit typ z factory – tu pak pouze pouzije
na vytvoreni te sluzby. A u PresenterFactory tomu tak je
- Tomáš Votruba
- Moderator | 1114
@joseff Také na to občas narážím.
IMHO je to bug, jelikož už vlastních interface/class/factory to funguje v pořádku.
- David Matějka
- Moderator | 6445
@TomášVotruba a u tech vlastnich definujes u sluzby jak class tak factory?
- Tomáš Votruba
- Moderator | 1114
@DavidMatějka To mi nedává smysl, to je jako kdybych uváděl
implementaci i interface.
Factory je typ třídy.
Jde spíše o to, že když si vyžádám
ProductRepositoryInterface
i ProductRepository
,
očekávám a dostanu to samé. Stejně tak pro ProductFactory
a
ProductFactoryInterface
apod.
- David Matějka
- Moderator | 6445
@TomášVotruba kdyz u sluzby uvedes factory i class, tak jak to je u presenter factory, tak nette DI tou uvedenou tridou rikas, ze IPresenterFactory je typ sluzby a PresenterFactory je implementace. A v pripade, ze je uvedeny oboje, tak se nette nesnazi zjistit typ z te factory. Kdybys uvedl pouze factory, nette zjisti, ze je to typu PresenterFactory a bude to fungovat.
EDIT:
Konkretne tenhle radek: https://github.com/…rBuilder.php#L423
jak vidis, class resolvnuta z factory se pouzije pouze pokud neni specifikovana
class u sluzby
EDIT2:
Ke zmene chovani doslo myslim v 2.3. Ale ne kvuli nejake zmene v nette/di,
ale kvuli zmene definice sluzeb, ktere pouzivaly
pouze class u definice, nyni je jako class interface a implementace je jako
factory, jak uz jsem zminoval.
Nevim, jestli je to zamysleny nebo nezamysleny BC break, ale myslim, ze je to lepsi – zacatecnici casto vyzaduji konkretni implementaci (napriklad SmtpMailer) namisto IMaileru
- Tomáš Votruba
- Moderator | 1114
@DavidMatějka Chápu jak to funguje, jen je to zbytečně WTF.
Píšeš, že „IPresenterFactory je typ sluzby a PresenterFactory je implementace“.
To již nese vlastní kód třídy
class PresenterFactory implements IPresenterFactory
.
- David Grudl
- Nette Core | 8228
Jelikož pomocí addService() lze vyměnit instanci Nette\Application\PresenterFactory za jinou, Nette se nemůže spolehnout na toho, že tam bude tento objekt, takže při statické kompilaci s ním vůbec nepočítá, tj. počítá jen s interfacem Nette\Application\IPresenterFactory.
- Tomáš Votruba
- Moderator | 1114
K čemu je vlastně nutné uvádět interface takto ručně?
Chybová hláška, která ověřuje typ třídy, mi taky párkrát zamotala hlavu, jelikož k jejímu původu se člověk musí dopátrat až sem.
Toto ověření by IMHO mělo probíhat až na úrovni, kde je závislost vyžadována. Stejně jako u vlastních registrací tříd.
- David Grudl
- Nette Core | 8228
Nutné to není. Pokud ale uvedu interface IPresenterFactory
,
hledí se na službu jako na IPresenterFactory
, nikoliv jako na
PresenterFactory
. Takže ji mohu v runtime nahradit jinou
instancí, která nemusí být PresenterFactory
nebo její potomek,
ale jakákoliv jiná implementace IPresenterFactory
.
Vlastně tím nastavením třídy zúžím, jak se na ni dívá DI (a potažmo i getByType), a rozšířím, za co může být za běhu nahrazena.