Proč vyhazuje $container->getByType(‚Nette\Application\PresenterFactory‘); error?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
joseff
Člen | 233
+
+1
-

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?

Unlink
Člen | 298
+
0
-

Lebo Nette\Application\IPresenterFactory a Nette\Application\PresenterFactory je rozdiel

a v kontajneri je registrovaný len ten interface.

David Matějka
Moderator | 6445
+
0
-

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
+
0
-

@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
+
0
-

@TomášVotruba a u tech vlastnich definujes u sluzby jak class tak factory?

Tomáš Votruba
Moderator | 1114
+
0
-

@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
+
0
-

@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
+
0
-

@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
+
0
-

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
+
0
-

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
+
0
-

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.