Di, containery v spolupraci s komponentami, modelmi…

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

Zdravicko,

kedze DI je tema ktoru sledujem od kedy sa tu na fore objavila (je mi jasne na co to je, preco to je a pod…) ale este som to realne nepouzil.

Skor mam otazku na nejaku tu napovedu…

Problem:

Klasicka aplikacia ma moduly, presentery, modely, komponenty… Zatial vsetko po starom.

Zacnem zlahka modelmi, kazdy model by mal dostat zavislosti tj. vo vacsine pripadov je to pripojenie k DB (nejaky ten layer) co by som asi riesil ako factory. Dajme tomu, ze tam predavam len to pripojenie co je jeden param v konstruktore co je este OK. Ak ich tam zacina byt viac pouzijem Nette\DI\Container (napr. vo vlastnej uprave). Este stale OK. Ale nie vsetky modely maju tie iste zavislosti a tu je u mna problem. Kto ma toto riesit? Ta factory ma vediet aky container (inak nakonfigurovany) nasupovat modelu do kontruktoru? Alebo vsade pchat jeden container pre modely, co je zrejme blbost.

Potom tu mame komponenty, v presenteroch su na ne tovarne. Ale aj tie komponenty maju, mozu mat, zavislosti a tu uz som v koncoch ako toto vyriesit :-)

Dik za odpovede, lebo mi tato tema pride ako tema modelov (kazdy si ide opat vlastnou cestou)

PS: nakoniec, pockam na PS kde budem do niekoho injektovat beer a on zodpovie na pripadne otazky :-D

Filip Procházka
Moderator | 4668
+
0
-

newPOPE napsal(a):

Ak ich tam zacina byt viac pouzijem Nette\DI\Container (napr. vo vlastnej uprave). Este stale OK. Ale nie vsetky modely maju tie iste zavislosti a tu je u mna problem. Kto ma toto riesit? Ta factory ma vediet aky container (inak nakonfigurovany) nasupovat modelu do kontruktoru? Alebo vsade pchat jeden container pre modely, co je zrejme blbost.

V první řadě bych pochyboval o správnosti návrhu modelu, který potřebuje více jak 3–4 jiné služby. Pokud nějaký takový je, asi bych se s tím moc nepatlal a dal mu hlavní container. Ale to je spíš o lenosti, čistější by to asi bylo, jak píšeš, injectnout do služby nový context.

A pak taky můžeš jít cestou opačnou, napsat nějaký ModelLocator. Lehký nástřel zde, nebo ve srigiho receptu.

Potom tu mame komponenty, v presenteroch su na ne tovarne. Ale aj tie komponenty maju, mozu mat, zavislosti a tu uz som v koncoch ako toto vyriesit :-)

Komponenty se do rodičů (takže i do Presenteru) dají připojit pomocí metody setParent, což se děje automaticky, pokud v továrničce metodu nepřipojíš přes constructor, ale vrátíš ji.

Constructor pak můžeš překrýt (což je náchylné na neviditelné problémy) a předávat v něm závislosti. Tady ovšem platí pravidlo, abys předešel problémům, volej rodiče.

public function __construct()
{
	parent::__construct();
}

Tohle je základ. Potom můžeš s constructorem už dělat různá kouzla.

Jeden příklad na závěr: Grinder\Grid a továrnička nebo inicializace v presenteru

Honza Marek
Člen | 1664
+
0
-

newPOPE napsal(a):

Zacnem zlahka modelmi, kazdy model by mal dostat zavislosti tj. vo vacsine pripadov je to pripojenie k DB (nejaky ten layer) co by som asi riesil ako factory.

Jako factory pojmenováváš tu closuru, kterou se přidává služba ($container->addService('Jmeno', $factory))?

Ak ich tam zacina byt viac pouzijem Nette\DI\Container (napr. vo vlastnej uprave).

Větší počet parametrů přece ničemu nevadí. Nette\DI\Container by se neměl do modelu vůbec dostat.

Ale nie vsetky modely maju tie iste zavislosti a tu je u mna problem.

Nevím proč je to problém. Každý model (modely budou služby) bude mít svojí „factory“.

$container->addService('ArticleModel', function ($container) {
	return new ArticleModel($container->database, $container->UserModel);
});


$container->addService('UserModel', function ($container) {
	return new UserModel($container->database);
});

Potom tu mame komponenty, v presenteroch su na ne tovarne. Ale aj tie komponenty maju, mozu mat, zavislosti a tu uz som v koncoch ako toto vyriesit :-)

protected function createComponentArticle()
{
	$control = new ArticleControl;
	$control->setModel($this->context->ArticleModel);
	return $control;
}
newPOPE
Člen | 648
+
0
-

Diky, za ‚polopatisticky‘ popis (snazil som sa pytat laicky, nech to pomoze aj inym) :-)

@hosipLan

  • 3–4 sluzby, slo mi o myslienku 1-N sluzieb

@Honza Marek

  • to ze by sa tam nemal dostat to mi je jasne, ale ono to s tym poctom parametrov je „debata do nekonecna“, mne osobne uz vadia viac ako 3 :-), druhemu to zas az tak vadit nemusi…

Ono pride mi to ako, ze vytvorim objekt a ten musim v extr. pripadoch na dalsich 10 riadok nastavovat ci uz cez kontruktor( popr. settery ) alebo predam kontext a on sa nastavi sam podla neho. Ale to ako hovorim, to je dost subjektivne (filozoficke)

  • co sa tyka tych komponent, vdaka :-)
22
Člen | 1478
+
0
-

Mě by spíš zajímal správný postup, jak získat třeba httpRequest v modelu?:
přes Environment po staru:

...
$request = Environment::getHttpRequest();
...

a správně přes DI?

Filip Procházka
Moderator | 4668
+
0
-

Když pominu logiku získávání služby v M co patří do V nebo P …

pomocí konfigurace

services:
	myModel: MyModelClass
	arguments: ['@httpRequest']

v bootstrap.php

$configurator->container->addService('myModel', function (Nette\DI\Container $container) {
	return new MyModelClass($container->httpRequest);
});

ve vlastním Configuratoru

public function createServiceMyModel(Nette\DI\Container $container)
{
	return new MyModelClass($container->httpRequest);
}

Editoval HosipLan (14. 6. 2011 14:58)

Tharos
Člen | 1030
+
0
-

@22: Na co jej v modelu potřebuješ? Suchá teorie praví, že model by o nějakém http requestu neměl vědět. :)

Nicméně, abych taky sdělil něco užitečného, předej potřebné hodnoty modelu tam, kde jej inicializuješ. To bude většinou v presenteru (kde máš možnost dostat se k http requestu přes container předávaný presenteru).

EDIT: To už je takový folklór, že mou odpověď vždycky někdo přesně o dvě minuty předběhne. ;)

Editoval Tharos (14. 6. 2011 15:01)

newPOPE
Člen | 648
+
0
-

Tharos napsal(a):
Nicméně, abych taky sdělil něco užitečného, předej potřebné hodnoty modelu tam, kde jej inicializuješ. To bude většinou v presenteru (kde máš možnost dostat se k http requestu přes container předávaný presenteru).

Mam za to, ze model startuje mimo prezenter, ja si ho len vytiahnem z contextu ako service, alebo mas na mysli nastavit ten httpRequest cez setter? To by mi prislo trocha mimo. (Nieco ako ze nastartujem motor a olej dodam neskor)

Editoval newPOPE (14. 6. 2011 15:12)

22
Člen | 1478
+
0
-

@Tharos: neměl jsem na mysli model přesně, jsem jen plácl, aby bylo jasné co myslím. Myslel jsem v podstatě jakoukoliv třídu, která potřebuje vědět něco o aplikaci.

@Hosiplan:
to je ono, až teď jsem pochopil, že v neonu se můžu takto odvolat na části kontejneru

services:
        myModel: MyModelClass
        arguments: ['@httpRequest']

Editoval 22 (14. 6. 2011 15:13)

Filip Procházka
Moderator | 4668
+
0
-

@newPOPE: Je tu totiž ještě přístup, kde modely nemáš v DI Container, ale instanciuješ je ve startup v presenteru a tam je plníš závislostmi. Což může někomu vyhovovat…

protected function startup()
{
	parent::startup()

	$this->model = new MyModelClass($this->context->httpRequest);
}

Což je takový mezi-krok, mezi opuštěním Environment, ale držením se z části DI a zčásti starých zvyků a plným přechodem na DI.

Pokud se člověk chce ale držet DI, pak takový model patří do Containeru

Editoval HosipLan (14. 6. 2011 15:32)

22
Člen | 1478
+
0
-

ještě by mě zajímalo, jestli jde nějak v neonu zapsat:

$configurator->container->addService('service1', function($container){
	return new Service1($container->params->productionMode);
});
Filip Procházka
Moderator | 4668
+
0
-
services:
	class: Service1
	arguments: ['%productionMode%']
22
Člen | 1478
+
0
-

díky, hranatý závorky chyběly .-)

srigi
Nette Blogger | 558
+
0
-

22 napsal(a):
to je ono, až teď jsem pochopil, že v neonu se můžu takto odvolat na části kontejneru

Mohol by si pls len tak, v ramci OT napisat, ako dlho ti trvalo pochopit tento zapis? Zaujima ma to preto, ze v doku to nie je a zo zdrojaku sa to nauci malokto. Zaujima ma polcas rozpadu, ziskania tejto knowledge. U mna cca 2 tyzdne po vzniku temy „Finalizace DI“ ;)

Editoval srigi (14. 6. 2011 19:33)

22
Člen | 1478
+
0
-

@srigi lol, tak mně začal běžet čas od té chvíle, co jsem se tam bavili o tom configu zde

@Hosiplan:

arguments: ['%test%']

problém je, že tam v rámci %test% nedostanu pole takto, nejde to? nebo nevím jak? Asi to nejde, podle sirgiho tutoriálu. Proč tomu tak ale je?

srigi v tutoriálu uvádí:

  • skalárne typy: „string“, int
  • placeholdery: %database.host% (bodková syntax zatiaľ nebola backportovaná do bety!)
  • odkazy na iné služby: @dbConnection

Editoval 22 (14. 6. 2011 19:43)

srigi
Nette Blogger | 558
+
0
-

22 napsal(a):
problém je, že tam v rámci %test% nedostanu pole takto, nejde to? nebo nevím jak? Asi to nejde, podle sirgiho tutoriálu. Proč tomu tak ale je?

Ide tam predat este to explicitne zapisane pole (sakra, mal by som to do clanku doplnit):

services:
	fooService:
		class: fooService
		arguments:
			- foo
			- bar
			#alebo ['foo', 'bar']

Dovod preco tam nejde predat cele pole je tento riadok. Skutocny dovod, preco je tam ta podmienka, musi zodpovedat niekto povolanejsi.

Editoval srigi (14. 6. 2011 20:01)

22
Člen | 1478
+
0
-

tak ale to tam nemusím dávat v tomot případě jako arguments, ale pošlu to jako option, ne-e?

Editoval 22 (14. 6. 2011 20:06)

Filip Procházka
Moderator | 4668
+
0
-

To je přeci snadné, preg_replace_callback neumí vracet nic jiného než scalar. Posílal jsem patch, který to řeší. Ale jak je vidět, je to tfuj milion podminek a sexy to zapsat nejde. Takže to bylo zamítnuto :)

Teyras
Člen | 81
+
0
-

Jakýkoliv způsob, jak předávat pole parametrů službám by byl super a myslím, že nás, kterým to chybí, není málo… To, že to nejde sexy zapsat zajímá jen zlomek lidí, i když je to trošku smutný…

Filip Procházka
Moderator | 4668
+
0
-

Tak to zkus napsat lépe, třeba to David pullne :)

22
Člen | 1478
+
0
-

Teyras napsal(a):

Jakýkoliv způsob, jak předávat pole parametrů službám by byl super a myslím, že nás, kterým to chybí, není málo… To, že to nejde sexy zapsat zajímá jen zlomek lidí, i když je to trošku smutný…

tak pořád to tam jde šoupnout v bootstrapu, že. Je to omezení jen pro config:

	test:
		a: aaa
		b: bbb
...
$container = $configurator->container;
$container->addService('servicer', function($container){
	return new Service($container->params->test);
});

Editoval 22 (15. 6. 2011 9:43)

Teyras
Člen | 81
+
0
-

HosipLan napsal(a):

Tak to zkus napsat lépe, třeba to David pullne :)

Určitě se pokusím :) Z nějakýho důvodu nerad cpu moc věcí do bootstrapu, i když je to asi jen iracionální blok…

22
Člen | 1478
+
0
-

zkus to ale rychle :-)

assassik
Člen | 43
+
0
-

Pár dní to tam už je:

DI\Container::expand supports %item.subitem% expansion

https://github.com/…893b8a183e02

grey
Člen | 94
+
0
-

assassik wrote:

Pár dní to tam už je:

DI\Container::expand supports %item.subitem% expansion

https://github.com/…893b8a183e02

Jde jim myslím o to, aby to umělo vracet i něco jiného než scalar…

Teyras
Člen | 81
+
0
-

22 napsal(a):

zkus to ale rychle :-)

Tak jsem se pokusil, ale nevím, jestli je to zrovna ono :) Přemejšlím, jestli to mám zveřejňovat, na svojí obhajobu můžu říct leda, že to funguje…

EDIT https://github.com/…584236dcb2e7

Editoval Teyras (20. 6. 2011 17:58)

David Grudl
Nette Core | 8133
+
0
-

HosipLan napsal(a):

To je přeci snadné, preg_replace_callback neumí vracet nic jiného než scalar. Posílal jsem patch, který to řeší. Ale jak je vidět, je to tfuj milion podminek a sexy to zapsat nejde. Takže to bylo zamítnuto :)

Nedošlo mi, že záměrem je získávat jiné neřetězcové proměnné, myslel jsem si, že jde jen o zanořování do polí.