Diskuse o vícenásobném načítání konfigů
- Tomáš Votruba
- Moderator | 1114
(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
...
?>
- wacco
- Člen | 11
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)
- uestla
- Backer | 799
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
@uestla:
moc nad tim spekulujes
- predat reflection do contructoru connection muzes bez i bez nastaveni setConnection danemu reflection, connection se k reflection pribinduje sam
- 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
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
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.
- David Grudl
- Nette Core | 8215
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.
- Honza Marek
- Člen | 1664
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
„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í:
- Mode a environment, console vs. production vs. development
- Název prostředí jako parametr v CLI
- Sekce [console] v config.ini?
Pokud by sekce neexistovali imho by se zjednodušilo i zpracování konfigurace.
- David Grudl
- Nette Core | 8215
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
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
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
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
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
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
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
@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
Míchají se tu hrušky s jablkama.
- 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. - 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.
- console production/development platí co stejné co pro sekce.
- 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. - sekce + includes lze používat dohromady, s tím, že
includes
zapíšeme docommon
, 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.
- Patrik Votoček
- Člen | 2221
@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
David Grudl napsal(a):
- 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
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
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í.
- Jan Tvrdík
- Nette guru | 2595
@hrach:
Řeší. Výsledná konfigurace se uloží do jednoho souboru. (Klíčem
cache jsou totiž mimo jiné parametry loadConfig
.)
- hrach
- Člen | 1838
@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
@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
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
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.
- David Grudl
- Nette Core | 8215
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
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
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.
- Patrik Votoček
- Člen | 2221
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í.
- Elijen
- Člen | 171
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
Vícenásobné načítání přes addConfig() implementované už je.
Uvažuju nad tím, že bych zrušil sekci includes
.
- Šaman
- Člen | 2658
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
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().