Diskuse o vícenásobném načítání konfigů

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Grudl
Nette Core | 8215
+
0
-

Tomáš Votruba
Moderator | 1114
+
0
-

(Je možné, že tyto změny nastaly již dříve a narazil jsem na ně až nyní, přesto je uvádím, aby s nimi ostatní mohli počítat.)

NotORM + FactoryLoader

Pokud někdo používá FactoryLoader pro NotORM, i zde může být změna. Config.neon beze změny.

<?php
// dříve
class FactoryLoader
{
	public function createPDO($di, $dsn, $un, $pass) {...}

	public function createNotORM($di, $pdo, $debug = NULL) {...}
}

// nyní
class FactoryLoader
{
	public function createPDO($dsn, $un, $pass) {...}

	public function createNotORM($pdo, $debug = NULL) {...}
}
?>

Config.neon – parameters < database

<?php
// dříve
common:
	database:
		type: mysql
		driver: mysql
		...

// nyní
common:
	parameters:
		database:
			type: mysql
			driver: mysql
			...
?>
Jan Jakeš
Člen | 177
+
0
-

Schmutzka: NotORM by teď mělo jít použít třeba i takto:

	services:
		notorm: NotORM(PDO('mysql:host=localhost;dbname=database', user, pass))
wacco
Člen | 11
+
0
-

Viem ze je to off-topic, ale chcel by som sa ta opytat David, ci by nebolo dobre sa zamysliet na vyriesenim tohto bugu https://github.com/…e/issues/160 . Pises ze uz sa chysta RC, ale mne tento bug pride ako dost podstatna vec a nie som sam. Uz som na to pozeral ci to nejako nefixnem ale neporadil som si. Dik za odpoved

Editoval wacco (13. 12. 2011 8:33)

Elijen
Člen | 171
+
0
-

Je nekde popsana funkcnost a pouziti v praxi onoho FactoryLoader? Diky

uestla
Backer | 799
+
0
-

Chci-li nastavit v setup nějakého servicu jiný service, který zatím nebyl vytvořen, ale sám onu první službu používá, jde tohoto nějak docílit?

V příkladu je v kolizi Connection a DiscoveredReflection. Děkuji.

services:
	database:
			class: 'Nette\Database\Connection'
			arguments:
				- '%database.driver%:host=%database.host%;dbname=%database.dbname%'
				- '%database.username%'
				- '%database.password%'
				- '@dbReflection'		# <---- ZDE
			setup:
				- setCacheStorage

	dbReflection:
			class: 'Nette\Database\Reflection\DiscoveredReflection'
			setup:
				- setConnection('@database')	# <---- A ZDE

Editoval uestla (13. 12. 2011 11:27)

hrach
Člen | 1838
+
0
-

@uestla:
moc nad tim spekulujes

  1. predat reflection do contructoru connection muzes bez i bez nastaveni setConnection danemu reflection, connection se k reflection pribinduje sam
  2. vcera bylo mj. pushnuto, ze connection ma metodu setDatabaseReflection, tedy muze byt predano pozdeji, akorat se vytvori automaticky conventionalreflection. a opet i v tomto pripade plati, ze se connection pribinduje (lepsi termin asi spis injectne) sam.
David Grudl
Nette Core | 8215
+
0
-

wacco napsal(a):

Viem ze je to off-topic,

Tak mi pověz, proč to sem píšeš?

ale chcel by som sa ta opytat David, ci by nebolo dobre sa zamysliet na vyriesenim tohto bugu https://github.com/…e/issues/160

Bylo! Samozřejmě. Je vás tu celá komunita, tak se zamyslete.

David Grudl
Nette Core | 8215
+
0
-

uestla napsal(a):

Chci-li nastavit v setup nějakého servicu jiný service, který zatím nebyl vytvořen, ale sám onu první službu používá, jde tohoto nějak docílit?

V tomto případě není potřeba mít dbReflection jako službu, takže stačí jako 4. argument uvést Nette\Database\Reflection\DiscoveredReflection() (tj. vytvoření nového objektu). Pokud bych to jako službu mít chtěl a pomineme-li, jak píše hrach, že setConnection se volá automaticky, lze zapsat:

services:
 	database:
 			class: Nette\Database\Connection(...)
 			setup:
				- @dbReflection::setConnection(@database)

Tedy v setup může být volání metody i jiné služby a jako argument lze předat sebe.

Ot@s
Backer | 476
+
0
-

Kdyby někdo narazl na chybu Found sections ‚common‘, ‚production‘, ‚development‘, ‚console‘ in configuration, but corresponding extensions are missing (při použití includes v neonu), tak oprava bugu je nahlášena zde.

David Grudl
Nette Core | 8215
+
0
-

To není bug, sekce skutečně lze používat jen v primárním a nikoliv inkludovaném konfiguráku. Použití sekcí unvitř inkludovaného souboru by vedli k „diamond“ problému podobnému vícenásobné dědičnosti.

pesha
Člen | 2
+
0
-

Jen takový detail – je nutné upravit i konstanty v index.php

Honza Marek
Člen | 1664
+
0
-

Současné chování includes mi přijde taky hodně matoucí a nepraktické. Chtěl jsem includes použít pro vložení neverzovaného lokálního konfiguračního souboru a nešlo to, protože includovat se dá jen v sekcích a ty sekce jsou prý potřeba vždy.

Zhruba takhle by v současném Nette vypadal konfigurák, který by dělal to co chci:

common:
    includes:
        - config.common.local.neon
production < common:
development < common:
    includes:
        - config.development.local.neon
console < common:
    includes:
        - config.console.local.neon

Přijde mi, že to hodně komplikují ty sekce. Stejné problémy by dokázalo vyřešit přímočařeji načtení více konfiguračních souborů. Jeden hlavní a druhý, který přepisuje nějakou lokální nebo testovací konfiguraci. Pak by includes nebylo v sekci, protože by žádná sekce nebyla :)

pekelnik
Člen | 462
+
0
-

„Stejné problémy by dokázalo vyřešit přímočařeji načtení více konfiguračních souborů.“ – Honza Marek

Přesně tak!

Sekce mi jdou na nervy už drahnou dobu, především kvůli dnes již evergreenu – tzv. „development console vs. production console“ problému.

Související:

Pokud by sekce neexistovali imho by se zjednodušilo i zpracování konfigurace.

David Grudl
Nette Core | 8215
+
0
-

Je to v tom úplně prvním příspěvku: Pokud použijete loadConfig('soubor.cosi', FALSE), sekce se používat nebudou. Máte-li pocit, že by sekce a include mělo fungovat jinak, jsem přístupný jakékoliv změně, ale zkuste si to předem důkladně promyslet – podle mého je to mission impossible.

pekelnik
Člen | 462
+
0
-

Já teď sekce v podstatě nepoužívám, takhle:

bootstrap.php

<?php
$configurator->loadConfig(array(
	'%configDir%/config.neon',
	'%configDir%/config.local.neon',
	));
?>

config.neon

common:
	database:
		{driver: "pdo_mysql", host: "", user: "", password: "", dbname: "", charset: "utf8"}
production < common:
development < common:
console < common:

config.local.neon

common:
	database:
		{driver: "pdo_mysql", host: "", user: "", password: "", dbname: "", charset: "utf8"}
production < common:
development < common:
console < common:

Editoval pekelnik (16. 12. 2011 4:51)

edke
Člen | 198
+
0
-

Honza Marek wrote:

… použít pro vložení neverzovaného lokálního konfiguračního souboru …

pekelnik wrote:
bootstrap.php

<?php
$configurator->loadConfig(array(
	'%configDir%/config.neon',
	'%configDir%/config.local.neon',
	));
?>

Super pani, kombinaciou tychto dvoch veci, teda includovanie lokalnej verzie neon a zaroven jej neverziovania sa da krasne poriesit vsetko, co som doteraz v configu elegantne riesit nevedel.

David Grudl
Nette Core | 8215
+
0
-

Ty mi tu mateš lidi, žádné loadConfig(array) nefunguje :-)
Bylo by možné to implementovat, ale připadá mi to jako duplicita includes.

Jan Tvrdík
Nette guru | 2595
+
0
-

Možnost načítat více souborů je věc, po které existuje poptávka už hodně dlouho (od první zmínky uplynulo skoro 2 a půl roku). Naposledy jsem se o ní (na Davidovu žádost) rozepsal v červnu (use case a návrh řešení included).

„includes“ jsou sice pěkná věc, ale pokud se Honza Marek nemýlí, tak na řešení té jediné věci, kterou jsem chtěl, aby dobře řešili, nejsou vhodné.

Pokud bude ale vícenásobné volání loadConfig fungovat stejně dobře, jako doposud, tak to asi není prioritní řešit.

Editoval Jan Tvrdík (16. 12. 2011 14:40)

hrach
Člen | 1838
+
0
-

Ve starsich verzich slo vice konfigu hacknout takhle:

$config = array();
$config[] = Nette\Config\Config::fromFile(APP_DIR. '/config.ini', $envName)->toArray();
$config[] = Nette\Config\Config::fromFile(APP_DIR. '/config.editorial.ini', $envName)->toArray();
$config[] = Nette\Config\Config::fromFile(APP_DIR. '/config.developer.ini', $envName)->toArray();

$config = Nette\ArrayTools::mergeTree($config[2], Nette\ArrayTools::mergeTree($config[1], $config[0]));
Env::loadConfig(new Nette\Config\Config($config));

Souhlasím s Honzou Tvrdikem, ze nepodpora vice konfigu je odstuda. Osobne nepotrebuji include, radej dvakrat neco includnu.

pekelnik
Člen | 462
+
0
-

Více konfiguračních souborů v Nette jednoduše takhle:

V příkladu nejsou záměrně použity tzv. „sekce“, protože se domnívám, že problém, který se snaží řešit, se v praxi řeší jinak – načtením více konfiguračních souborů.

Některé konfigurační soubory nemusí být vůbec verzovány a mohou sloužit jako tzv. lokální konfigurační soubory specifické pro daný stroj. Takhle se to používá jak na serverech, na kterých jsou aplikace nasazany a správce nemá zájem heslo do produkční databáze komukoliv dávat, tak na vývojářských stanicích kde pro změnu není zájem sdílet mnoho lokálních konfigurací s celým týmem.

bootstrap.php

<?php
$configurator->loadConfig(__DIR__ . '/config.neon', FALSE);
?>

Nastavením druhého parametru na FALSE dojde ke zrušení dělení konfigurace na sekce common, production, development a console – což je výchozí chování, které se v praxi ale ukazuje jako nevyhovující například kvůli zmíněnému problému „production console vs. development console“.

config.neon

includes:
	- config.local.neon
parameters:
	database: [driver: mysql, host: localhost, dbname: test, user: '***', password: '***']
php:
	date.timezone: Europe/Prague
services:
	database:
		class: Nette\Database\Connection
		arguments: ['%database.driver%:host=%database.host%;dbname=%database.dbname%', %database.user%, %database.password%, ..., Nette\Database\Reflection\DiscoveredReflection()]
		setup:
			- setCacheStorage()

config.local.neon

php:
	date.timezone: Europe/Paris
parameters:
        database: [driver: mysql, host: localhost, dbname: test, user: '***', password: '***']

Editoval pekelnik (16. 12. 2011 20:20)

Patrik Votoček
Člen | 2221
+
0
-

@pekelnik: to ti ale nebude fungovat podle očekávání…

Musel by jsi mít ten include naopak…

$configurator->loadConfig(__DIR__ . '/config.local.neon', FALSE);
David Grudl
Nette Core | 8215
+
0
-

Míchají se tu hrušky s jablkama.

  1. rozdělení konfigurace do více souborů je možné pomocí sekce includes v načítaném konfiguráku. I každý z takto načtených souborů může mít další includes a načítané soubory mohou být dokonce v různém formátu. Nicméně třeba pro konfiguraci služeb je NEON mnohem šikovnější než PHP/INI/XML/YAML.
  2. sekce jsou historická záležitost, co umožňovala udržovat více konfigurací v jednom souboru a neopakovat stejné údaje. V tuto chvíli jsou kvůli kompatibilitě defaultní a vypínají se přes FALSE. Změnit se to může, vymyslete jak.
  3. console production/development platí co stejné co pro sekce.
  4. vícenásobné volání loadConfig rozhodně možné není, předat mu jako argument pole taktéž ne. Implementovat by to bylo triviální, ale připadá mi to jako duplicita k includes. Byť obojí má své výhody a nevýhody.
  5. sekce + includes lze používat dohromady, s tím, že includes zapíšeme do common, protože sekce se zpracovávají dřív než includes. V inkludovaných souborech se už sekce nepoužívají. Žádnou komplikaci v tom nevidím.
pekelnik
Člen | 462
+
0
-

@pekelnik: to ti ale nebude fungovat podle očekávání…

Naopak :) funguje to skvěle.

Patrik Votoček
Člen | 2221
+
0
-

@pekelnik: ale v tvém příkladě **má přednost config.neon před config.local.neon **. Takže buďto špatně zvolené názvy nebo mě něco uniká.

nanuqcz
Člen | 822
+
0
-

David Grudl napsal(a):

  1. vícenásobné volání loadConfig rozhodně možné není, předat mu jako argument pole taktéž ne. Implementovat by to bylo triviální, ale připadá mi to jako duplicita k includes. Byť obojí má své výhody a nevýhody.

Rád bych načítal všechny .neon soubory, které mi najde Nette Finder. Přimlouvám se tedy k implementaci loadConfig(array). Jaké výhody má includes oproti vícenásobnému volání loadConfig?

hrach
Člen | 1838
+
0
-

Zrušil bych include a zavedl vicenasobne volani. Je to:

  • na prvni pohled viditelne, co „ma vetsi prioritu“
  • jednoduche reseni ze neco ma sekce a neco nema (via volitelny parametr)
  • jednoducha implementace pro beh na ruznych masinach, prostredich, neni treba nic ohybat, jednoduse se daji specifikovat v php podminky, kdy co nacitat…, atp.

Vrtakova uprava je zajima, nicmene je mi proti srsti zase ta „poloautomatika“.

Jan Tvrdík
Nette guru | 2595
+
0
-

Vícenásobné volání (které jistou dobu „omylem“ funguje) nedokáže některé věci řešit. Spolehlivé řešení je povolit loadConfig(array(...)) nebo použít nějakou formu include resp. extends. Při povolení loadConfig(array(...)) přijdeš o možnost určit, že něco sekce má a něco nemá.

Výhoda sekcí oproti více souborům (což považuji za pěkný nápad) je, že v případě krátkých konfiguračních souborů je všechno na jednom místě. Samostatné soubory mi přijdou praktičtější v případě rozsáhlejších aplikací.

hrach
Člen | 1838
+
0
-

@Jan Tvrdík:
v odkazovaném vláknu jsou zméněné problémy (již) irelavantní. Startování služby myslím už neexistuje, ne? A generování dvou souborů? Když pominu, že to nevidím jako problém, tak to tvoje loadConfig(array(...)) vůbec neřeší, ne?

Jan Tvrdík
Nette guru | 2595
+
0
-

@hrach:

Řeší. Výsledná konfigurace se uloží do jednoho souboru. (Klíčem cache jsou totiž mimo jiné parametry loadConfig.)

hrach
Člen | 1838
+
0
-

@Jan Tvrdik:
to si podle me jen nedokazes predstavit dostatecne abstraktne. Aktualne loadConfig vola createContainer, ktery nacita konfiguraci. Nicmene kdybychom se na to vrhli, muzes se dostat k necemu ala

$configurator->loadConfig('config.neon');
$configurator->loadConfig('config.local.neon', FALSE);

$container = $configurator->createContainer();

Osobne bych to takhle (pre)delal i bez moznosti nacitat vic konfigu, je totiz wtf, ze metoda loadConfig vraci container. Vyse zminene reseni nema imo problem generovat jeden SystemContainer.

Jan Tvrdík
Nette guru | 2595
+
0
-

@hrach: +1 pro tvůj návrh řešení, snad tam není nějaký fatální problém. Skutečnost, že loadConfig vrací systémový kontejner je skutečně trochu podivná. Možná místo createContainer volat getContainer, který by v případě neexistence containeru zavolal privatní createContainer.

pekelnik
Člen | 462
+
0
-

Nicmene kdybychom se na to vrhli, muzes se dostat k necemu ala

$configurator->loadConfig('config.neon');
$configurator->loadConfig('config.local.neon', FALSE);

$container = $configurator->createContainer();

Osobne bych to takhle (pre)delal i bez moznosti nacitat vic konfigu, je totiz wtf, ze metoda loadConfig vraci container. Vyse zminene reseni nema imo problem generovat jeden SystemContainer.

+1

Filip Procházka
Moderator | 4668
+
0
-

Já bych šel do extrému.

Nemyslím si, že nějaké loadConfig je vůbec potřeba volat. Na všechno by mohla stačit současná implementace include + dohledávání configu pro prostředí v jedné složce.

Pokud by někdo potřeboval něco jiného, podědil by si Configurator

class MyConfigurator extends Nette\Config\Configurator
{
	protected function getConfigFile($params)
	{
		return $params['appDir'] . '/config/config_' . $params['environment'] . '.neon';
	}
}
$configurator = new MyConfigurator();
$container = $configurator->getContainer(); // volá createContainer()

$container->application->run();

viz: https://github.com/…r/app/config

Samozřejmě se zachováním zpětné kompatibility, protože na metodu loadConfig by nebyla potřeba sahat.

nanuqcz
Člen | 822
+
0
-

hrach napsal(a):

Nicmene kdybychom se na to vrhli, muzes se dostat k necemu ala

$configurator->loadConfig('config.neon');
$configurator->loadConfig('config.local.neon', FALSE);

$container = $configurator->createContainer();

Taky +1

David Grudl
Nette Core | 8215
+
0
-

Souhlas, loadConfig() vracející kontejner se mi nelíbí. Nelíbí se mi ani to FALSE. Co to udělat tak, že 1× loadConfig použije standardně sekce, vícekrát loadConfig bude bez sekcí? Blbost…

BTW, nelíbí se mi ani setCacheDirectory() pro tempDir, což taky si nejsem jist jak změnit, viz https://github.com/…tte/pull/426

hrach
Člen | 1838
+
0
-

Zrušení „FALSE“ mi nepřijde jako vhodné. Je to hodně wtf, uvažmě následující situaci:

$configurator->loadConfig('config.common.neon'/*, FALSE*/);
$configurator->loadConfig('config.modes.neon');

Ve smyslu, nejdriv neco, co na sekcich neni zavisle – obecne volby, ale pak to chci prepsat pomoci konfiguraci podle prostredi

Honza Marek
Člen | 1664
+
0
-

David Grudl napsal(a):

Souhlas, loadConfig() vracející kontejner se mi nelíbí.

Z estetického hlediska bych se spokojil s tím, kdyby metoda createContainer byla public. Používal bych tu.

David Grudl
Nette Core | 8215
+
0
-

Pokud bude createContainer() public, zrušil bych getContainer().

pekelnik
Člen | 462
+
0
-

+1

Patrik Votoček
Člen | 2221
+
0
-

David Grudl napsal(a):

Co to udělat tak, že 1× loadConfig použije standardně sekce, vícekrát loadConfig bude bez sekcí?

Používám jeden config a bez sekcí. Takže nelíbí.

Honza Marek
Člen | 1664
+
0
-

Hlavně je to WTF magie.

Elijen
Člen | 171
+
0
-

hrach napsal(a):

Zrušil bych include a zavedl vicenasobne volani. Je to:

  • na prvni pohled viditelne, co „ma vetsi prioritu“
  • jednoduche reseni ze neco ma sekce a neco nema (via volitelny parametr)
  • jednoducha implementace pro beh na ruznych masinach, prostredich, neni treba nic ohybat, jednoduse se daji specifikovat v php podminky, kdy co nacitat…, atp.

Vrtakova uprava je zajima, nicmene je mi proti srsti zase ta „poloautomatika“.

Plne souhlasim. Take bych radeji mel nacitani configu vice pod kontrolou. Pridavani dalsi a dalsi funkcnosti do NEONu mi prijde na prvni pohled cool, ale nejsem si jist, zda je to krok spravnym smerem.

David Grudl
Nette Core | 8215
+
0
-

Vícenásobné načítání přes addConfig() implementované už je.

Uvažuju nad tím, že bych zrušil sekci includes.

Filip Procházka
Moderator | 4668
+
0
-

Rozhodně nerušit! :(

hrach
Člen | 1838
+
0
-

Jsem pro :))

Ot@s
Backer | 476
+
0
-

David Grudl napsal(a):

Uvažuju nad tím, že bych zrušil sekci includes.

Prosím nerušit. Kdo je nechce, nemusí je vůbec používat.

Šaman
Člen | 2658
+
0
-

Incluses bych rád používal, připadá mi to super.
Odděluje to logiku presenteru (aplikace) od logiky configu.
Když rozdělím config na dva soubory (třeba se mi rozrůstá některá sekce, tak ji vyčlením vlastní soubor), tak mi připadá lepší tuto změnu zavést jen do configu a nesahat do bootstrapu.

Vícenásobné načítání je taky dobré, ale spíš pro jiný případ – třeba při existenci config.local.neon přepíše lokalní nastavení ta předchozí. To už je aplikační logika, je to nějaké naprogramované chování a do .php souboru patří.

Při použití include configu by se ale klidně mohla vyhazovat výjimka v případě, že se snažím několikanásobně (duplikovaně) nastavit nějaké údaje. Je to podle mě chyba, stejně jako několik tříd stejného jména. Vzniká problém s prioritou a tak..

Při několikásobném načítání je jasné, že později zavolaný má prioritu a přepíše dřívější nastavení.

David Grudl
Nette Core | 8215
+
0
-

Ten opakující se argument s prioritou nechápu. Vždyť při načítání více includes funguje priorita úplně stejně, jako při načítání více souborů pomocí addConfig().