Přechod z Environment na DI pro zelenáče

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

Začátečník nejsem, ale pro verzi 2 očividně ano. Rád bych udělal v bootstrap.php něco takovéhoto:

require LIBS_DIR . '/Nette/loader.php';

$environment = String::webalize(php_uname('n'));
Environment::setName($environment);

A v config.ini:

[lisa < development]
; computer of Honza Javorek
variable.sizeOfPenis = "38"
database.password = "100nozka"

Dělám to tak už dlouho a je to skvělý postup, jak rozlišit různé počítače (různé vývojáře apod.), které mají své vlastní nastavení. Bohužel, nic jako Environment::setName() jsem v novém Nette nenašel a https://doc.nette.org/cs/configuring je prázdné. Navedl by mě někdo na správnou cestu?

Jediné, co mě ještě napadlo, je mít více konfiguráků pro více počítačů. Např.:

$environment = String::webalize(php_uname('n'));
$configurator = new Nette\Configurator;
$configurator->loadConfig(__DIR__ . "/config-$environment.neon");

Jenže to mi přijde hloupé. Proč?

  1. Přicházím o dědičnost různých nastavení a musím udržovat několik konfiguráků (náchylnost k chybám když zapomenu).
  2. Autodetekce production a development je mi pak už úplně na nic, mám zcela různé konfigurace pro různé stroje.

Editoval littlemaple (11. 6. 2011 15:21)

Patrik Votoček
Člen | 2221
+
0
-
$environment = String::webalize(php_uname('n'));
$configurator = new Nette\Configurator;
$configurator->loadConfig(__DIR__ . '/config.neon', $environment);
honzajavorek
Člen | 57
+
0
-

Díky moc :) . A můžu ještě jeden dotaz? Nechce se mi zakládat nový topic. Když využiji slavnou DI a nechci použít Environment, jak se ke kontextu dostanu kdekoliv z aplikace? Jediné místo, kde mám možnost dostat se ke konfiguraci nebo k přihlášenému uživateli, jsem našel v podobě Presenter::getContext(). Jak se k tomu ale dostanu z modelu, z IAuthenticatoru, z komponenty, …? Pokud nechci použít Environment::...?

EDIT: Jde mi o nějakou best practise. Asi chápu, že se to tam má navzájem nějak všechno předávat. Z komponenty to vezmu $this->presenter->context, ale co z věcí, které jsou tak nějak vedle? Mám modelům předávat context? Co když potřebuji context v tom IAuthenticatoru, což je zase další service?

Pozn.: Absence obsahu v https://doc.nette.org/cs/configuring je pro člověka, který se chce naučit používat to nové DI, docela frustrující. Fórum je zanesené tunami neplodných diskusí o tom jak bude DI v Nette vypadat, ale nejsou tu žádné funkční příklady nebo řešené problémy. Po půldni bádání a pročítání mám chuť to zabalit a použít buď postaru Environment, nebo dělat užitečnější věci než reverse engineering Nette. Snad hodinu jsem přicházel na to, že alternativa k Environment::getVariable('bubu') je $presenter->getContext()->params['bubu'].

Editoval littlemaple (11. 6. 2011 16:25)

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Asi takto, v modelové části aplikace by se nikde ke contextu přistupovat nemělo. Docvaklo mi to při primitivní ukázce na Poslední sobotě – vpodstatě ukázce poučky, že třídy nemají o nějakém contextu/DI containeru nic vědět. Co z konfiguráku je v modelu potřeba? Nějaká služba? Předat rovnou skrze konstruktor nebo setter. Data? Nejlépe opět v nějaké továrničce, třeba statické metodě, které jediné se konfigurační container (stejná instance jako v Presenteru v getContext()) předává.

Doufám, že tu nešířím bludy. Přidám ještě primitivní ukázku, oboje někde z modelových tříd, prostě mimo presentery.

# továrnička na dibi připojení
class MyDibiFactory
{
	public static function createConnection(\Nette\DI\Container $cont)
	{
		return dibi::connect((array) $cont->params->database)
	}
}

# modelová třída využívající dibi
class MyModel extends \Nette\Object
{
	public function __construct(\dibiConnection $connection)
	{
		$this->connection = $connection;
	}
}

A v config.neon:

services:
	dibi:
		factory: MyDibiFactory::createConnection
	model:
		class: MyModel
		arguments: ["@dibi"]

A úplně na závěr proč to celé? Aby se dala instance dibi připojení jednoduše nahradit něčím jiným, třeba mockem v testech.

Editoval vojtech.dobes (11. 6. 2011 21:25)

nanuqcz
Člen | 822
+
0
-

Komponenta: Z komponenty by to mělo jít pokud vím

$this->getPresenter()->context

Model: Pokud se potřebuješ v modelu dostat k ostatním službám, tak bys měl i ten model registrovat jako službu v DI Containeru. Věci, které z DI Containeru budeš v modelu potřebovat, mu tam předáš jako parametr.

$cont = new Nette\DI\Container;

$cont->addService('ArticlesModel', function($cont) {
        $articles_model = new ArticlesModel();
        $articles_model->setNecoCoPotrebuju($cont->necoCoPotrebuju);
        return $articles_model;
});

P.S. V DI se teprve rozkoukávám, takže pokud jsem to napsal špatně, prosím zkušenější ať mě opraví O:-)

Editoval xxxObiWan (11. 6. 2011 16:20)

honzajavorek
Člen | 57
+
0
-

Díky, na tomto už se dá nějak stavět. Co řeším konkrétně:

  1. Mám v kontejneru službu Facebook, která mi poskytuje FB API. Pak mám v témže kontejneru IAuthenticator, který by ji rád využil. To mi asi ukázal xxxObiWan, díky.
  2. Databázové připojení. To ukazuje vojtech.dobes, díky, snad se tím proberu a pochopím to.

Samotné využití contextu v modelu teď nepotřebuju, ale měl jsem dojem, že jsem to kdysi využil (User), tak jsem se na to ptal taky. Možná je to ale špatný návrh.

Co mě dráždí:

  • Jak mám vědět, co psát do config.neon? Máš tam nějaké parametry factory, class, arguments a magické cosi ["@dibi"]. To je někde v dokumentaci, nebo jsi použil křišťálovou kouli? Nebo mám projít řádek po řádku config parser a z toho zjistit, jaký zápis tam funguje a co dělá?
hrach
Člen | 1838
+
0
-

@vojtech.dobes: myslim, ze namas pravdu, respektive neuplnou. Model nema nic vedet o globalnim (v nette treba rekneme aplikacnim) contextu. DI vubec neznamena, ze modelu nemuzu predat jeho vlastni kontext s potrebnymi sluzbami, jako je napr. connection.

@xxxObiWan: toto „Pokud se potřebuješ v modelu dostat k ostatním službám,tak bys měl i ten model registrovat jako službu v DI Containeru.“ taky imho neni pravda. To, ze nejaka instance potrebuje nejake sluzby z ni jeste nedela sluzbu. Samozrejme, to ze model ma vlastnosti sluzby je fakt, takze tudy by ta cesta mohla vest, ale dana citovana veta neni pravdiva.

edit: spis bych to definoval tak, ze ma vedet pouze o svem vlastnim kontextu.

Editoval hrach (11. 6. 2011 16:51)

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

@hrach: jasně, souhlasím. Nechtěl jsem to tím komplikovat :)

@littlemaple: počkat na dokumentaci :). Já to nějak vyčetl z examples a sandboxu, a taky určitě https://github.com/…rine-Sandbox. Stručné shrnutí:

  • class: třída, která bude přímo instancována
  • factory: statická metoda, která vrátí již hotovou instanci
  • arguments: pole argumentů, které se v řadě předají konstruktoru (neplatí při použití factory, té se předá přímo instance Containeru). Zde se výrazy %nazevPromenne% expandují na proměnné z configu, a výrazy "@nazevSluzby" na konkrétní služby, lze tedy jednotlivé služby skládat atd. (můj příklad výše)
  • tags: viz https://forum.nette.org/…cy-injection
  • run: true: zkratka pro tags: ['run']

Víc nevím a doufám že bludy stále nešířím.

Editoval vojtech.dobes (11. 6. 2011 21:21)

bojovyletoun
Člen | 667
+
0
-

Configurator je relativně nová část frameworku, proto bycho odkázal na téma DI ( Finalizace, Dependnency Injection, Co je Dependency Injection). Pokud nevíš, jak zapsat něco v „neon syntaxi“, použij PHP. Ostatně jak je vidět z temp/cache/Nette%5CConfigurator, tak konfigurace se kompiluje (Má na starosti Service Builder.

honzajavorek
Člen | 57
+
0
-

@vojtech.dobes Díky :)

@bojovyletoun Configurator zjevně potřebuju, pokud nechci použít Environment, od něhož mě pročítání fóra odrazuje. DI jsem pročetl, od Fabiena až po Nette Docs. To s Neon syntaxí je nepřesně řečeno – samozřejmě vím jak v ní něco napsat (http://ne-on.org/), ale tady jsem fakt nevěděl co do ní psát :)

Tharos
Člen | 1030
+
0
-

xxxObiWan napsal(a):

Komponenta: Z komponenty by to mělo jít pokud vím

Na tohle pozor, zaznelo to tu uz dvakrat a je to prave ukazkove poruseni DI. :) Ta komponenta si nema takhle sama natvrdo sahat pro nejakou zavislost, ta ji ma by dana. Idealne v tovarnicce pres konstruktor, budto formou kontaineru, anebo jeste lepe primo v podobe instanci, ktere potrebuje. Pokud formou kontaineru, Nette-way je vyroba kontaineru na miru, ve kterem bude jen to skutecne potrebne. Tj. nepredavat zbytecne ten kontainer z presenteru.

bojovyletoun
Člen | 667
+
0
-

littlemaple napsal(a):
o s Neon syntaxí je nepřesně řečeno – samozřejmě vím jak v ní něco napsat (http://ne-on.org/), ale tady jsem fakt nevěděl co do ní psát :)

Takhle jsem to myslel.

nanuqcz
Člen | 822
+
0
-

@Tharos: Jo, máš pravdu. Pomalu mi tady díky fóru začíná docházet plno věcí, ohledně DI :-) Díky

honzajavorek
Člen | 57
+
0
-

Jak změním topic? Tenhle už není moc aktuální. Hodilo by se spíš něco jako „Přechod z Environment na DI pro zelenáče“ :)

22
Člen | 1478
+
0
-

Obecně bych byl pro zavedení nové sekce fóra pro DI, aby se jasně rozlišilo, že lze používat obě cesty, jak DI, tak Environment.

nanuqcz
Člen | 822
+
0
-

@22: To se mi líbí (pokud na tom nějak záleží :-D)

Filip Procházka
Moderator | 4668
+
0
-

Struktura, jak konfigurovat služby. A taky byjste měli začít rozlišovat mezi Dependency Injection a Dependecy Injection Containerem :) Jedno je princip, druhé nástroj, ve zkratce zde.