Volitelné injektování do modelu

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

Ahoj,
řeším problém, jak se vyhnout Nette\DI\ServiceCreationException: Service ‚31‘: Class TestDI does not exist způsobené tímto úryvkem kódu v modelové třídě:

protected $testDI;

	public function injectTestDI(TestDI $parm = null)
	{
		$this->testDI = $parm;
	}

Pokud třída TestDI fyzicky neexistuje (tzn. smažu složku s modulem), nette DI ContainerBuilder vyvolá výše zmíněnou vyjímku. Zajímavé však je, že pokud tento samý kód použiju v Presenteru, vše funguje jak má a pokud třída chybí, nic se neděje a dosadí se správně $testDI = null;

Btw inject: yes je nastaveno.

Zkoušel jsem DI kontajner všelijak debuggovat a porovnávat co je jinak v případě Presenteru a v případě Modelu ale nedodebugoval jsem se výsledku.

Díky za postřehy, případně rady jak děláte „opravdu modulární“ aplikace v Nette vy.

Editoval lukyer (14. 11. 2014 21:58)

Azathoth
Člen | 495
+
0
-

V modelových třídach bys měl spíš používat injekci pomocí setterů a ne metody inject.

lukyer
Člen | 33
+
0
-

Vím o tom, ale jedná se o velký projekt, který je kompletně takto napsaný a moc se to nikomu přepisovat nechce. Navíc nevím, jestli by setter vůbec vyřešil problém jak nastavit neexistující objekt (resp. null místo objektu pokud třída neexistuje).

Azathoth
Člen | 495
+
0
-

@lukyer pokud se nepletu, tak setter se používá právě na závislosti, které nevyužiješ vždycky, tedy dělá to samé jako inject, akorát k tomu nemusíš nastavovat inject: yes v config.neon, tedy závislost je null a našte se až ve chvíli, kdy ji potřebuješ.

lukyer
Člen | 33
+
0
-

@Azathoth zkusil jsem a bohužel to je trošku jiný koncept. Já potřebuju, ať se config.neon vypořádá s tím, že pokud volám setter - setTestDI(@SluzbaCoNemusiExistovat) tak pokud služba zrovna neexistuje (někdo dal DELETE na složku s daným modulem), tak dosadí NULL do argumentu tohoto setteru. Pokud ovšem služba zrovna existuje (někdo ten modul používat chce), tak dosadí službu klasicky tak jak to známe.

Je to pochopitelné? :D

pawouk
Člen | 172
+
+1
-

Ahoj, ta @sluzbaconemusiexistovat existovat musi. S tim nic nenadelas, ale muzes si to obalit tridou. Tedy setTestDi(@myServiceGetter::get(nazevSluzbyCoNemusiExistovat)) a tam si dat normalni if. Ale prijde mi divne ze neco takoveho potrebujes…

lukyer
Člen | 33
+
0
-

@pawouk Díky, tímhle workaroundem by to šlo. Nicméně mi pořád jde o to, proč Presenter takovou funkcionalitu má ale Model s inject: yes ne :/. Pokud se ptáš na use-case, jedná se o logovací modul, který ve velké aplikaci může nebo nemusí být. Prostě buď se tam do složky Modules nakopíruje fyzicky nebo ne. A v jednotlivých akcích různých modelů musí být volání „zaloguj tuto akci, pokud je logovací modul přítomen“. Zkus nastínit jak bys to řešil, možná dojdeme na stejný problém :-)

Šaman
Člen | 2665
+
0
-

To mi přijde moc velká magie. Řešení stylu: „jestli najdeš něco vhodného, tak to použij a jinak si to v tichosti udělej jinak“ zavání obrovským WTF faktorem při hledání podivného chování programu.
Rozhodně by bylo dobré aspoň přidat řádek do configu, pokud se přidá celý modul.

lukyer
Člen | 33
+
0
-

@Šaman samozřejmě se lokální module.config.neon daného modulu načte, definuje se tam mnoho věcí, takže config.neon je OK :)

pawouk
Člen | 172
+
0
-

@lukyer: Pokud to je tak jak říkáš, tedy „zaloguj tuto akci, pokud je logovací modul přítomen“ Tak myslím, že vůbec nemusíš tu službu strkat do toho objectku, ale udělat si událost v tom oběktu a tu pak vyvolat.

// objekt do kterého jsi strkal logger původně
class Control \Nette\Object {
   public $onAction;

   private funcion doSomeAction(){
		// tady udelas beznou akci
        // a po dokonceni zavolas event
        $this->onAction($this, $toCoChciLogovat); // muzes předat sám sebe, nebo to co budeš chtít logovat, to je na tobě
   }
}

Pak si na tuto událost nasadit tent tvůj logger pokud je přítomen, to uděláš v ControlFactory:

class ControlFactory extend \Nette\Object {

	private $container;

	public function __construct(Container $container){
		$this->container = $container;
	}

	public function create(){
		$new = new Control();
		if($this->container->hasService('..')) // nebo getByType to už je fuk jak to detekuješ..
			$logger = $this->container->getService('servicename');
			$new->onAction[] = function($control, $toCoChciLogovat) use ($logger){
				$logger->log($toCoChciLogovat);
			};
		}
	}
}