Změny v Nette\Config pro verzi 2.0
- David Grudl
- Nette Core | 8227
Poprosil bych o feedback kvůli chystaným změnám tříd
Nette\Config
. Proč vlastně nějaké změny?
Nette\Config\Config
byl z „magických důvodů“ potomkem ArrayObject srze Nette\Collection a zdědil pak podivné API (podrobněji)- zrušení Nette\Collection určitou změnu vyžaduje
- verze 1.0 dává možnost zhodnotit
Nette\Config
a přepracovat je blíž tomu, jak je reálně používáno - a je možné, že
Nette\Config
je overengineered - obsahuje statické třídy
- zodpovědnost samotné třídy
Nette\Config\Config
by se mohla rozdělit
Má představa je taková, že třída Nette\Config\Config by se mohla
zjednodušit až na úroveň primitivní přenosky dat s vlastností, že
k jejím prvkům lze přistupovat přes $config->item
a
zároveň přes $config['item']
. Váhám, zda neexistující
klíče mají vracet tiše NULL nebo upozornit – buď přes E_xxx nebo
výjimkou.
Dále jsou tu adaptéry pro načítání a ukládání konfigurace do
souborů. Mám za to, že schopnost ukládat nikdo nevyužívá (nebo ano?) –
tudíž bych ji odstranil. Také myslím, že nebyl nikdy využit interface
IConfigAdapter
, tudíž je nepotřebný. Statická třída
ConfigAdapterINI
by se tak mohla změnit na nestatickou
ConfigLoaderIni
. Mohl by se zachovat nějaký statický
syntaktický sugar
jako $config = ConfigLoaderIni::load('config.ini')
Schopnost definovat různé loadery pro různé přípony konfiguračního
souboru sice dělá Nette zcela nezávislé na formátu konfiguráků při
volání Environment::loadConfig()
, ale opět mám za to, že jde
o vlastnost využívanou zcela okrajově. Téhož lze dosáhnout pomocí
Environment::loadConfig(ConfigAdapterYaml::load('config.yaml'))
.
Co myslíte?
- Honza Marek
- Člen | 1664
Dále jsou tu adaptéry pro načítání a ukládání konfigurace do souborů. Mám za to, že schopnost ukládat nikdo nevyužívá (nebo ano?)
Ukládání využívá Ormion. A kdyby třída Environment uměla načíst více konfiguračních souborů, tak bych tim asi generoval nějaký nastavení aplikace.
Jo a Ormion využívá jen ConfigAdapterIni, stačí mi načíst a uložit pole, použití třídy Config by mi nepřineslo žádnou výhodu.
- David Grudl
- Nette Core | 8227
To ukládání využíváš jako určitou formu cache?
ad Environment a konfigurace: to nechme na další vlákno.
- David Grudl
- Nette Core | 8227
bazo napsal(a):
ja pouzivam ukladanie do ini suboru na ulozenie uzivatelskej konfiguracie napr. nastavenie tem, master hesla atd. rozhodne je to uzitocne. takze nerusit, skor vylepsit
A jak vylepšit?
- Honza Marek
- Člen | 1664
David Grudl napsal(a):
To ukládání využíváš jako určitou formu cache?
Tu funkci to má taky, ale oproti použití Nette\Cache tam je rozdíl v tom, že se uživatel do toho může podívat, upravit to a přidat další informace třeba o asociacích. Vlastně je to takový předgenerovaný skoroyaml.
- jasir
- Člen | 746
David Grudl napsal(a):
Má představa je taková, že třída Nette\Config\Config by se mohla zjednodušit až na úroveň primitivní přenosky dat s vlastností, že k jejím prvkům lze přistupovat přes
$config->item
a zároveň přes$config['item']
. Váhám, zda neexistující klíče mají vracet tiše NULL nebo upozornit – buď přes E_xxx nebo výjimkou.
Souhlas + tiché vracení NULL za předpokladu funkčnosti
isset($config['klic'])
.
Dále se mi zdá, že by bylo dobré:
- načítání více config souborů
- možnost zkratky pro přístup k prvkům v sekcích
$config['database/username']
- David Grudl
- Nette Core | 8227
Ukládání zruší veškerou dědičnost, uživatelské komentáře a případně expanduje proměnné. INI se nedá použít jako univerzální serializační formát, kvůli restrikcím – klíče mohou obsahovat jen cca alfanumerické znaky, v hodnotách nemůže být uvozovka. Tohle všechno je ale dáno technickou podstatou a nelze s tím nic dělat.
Nebo INI nahradit jiným formátem…
- pekelnik
- Člen | 462
David Grudl napsal(a):
Nebo INI nahradit jiným formátem…
YAML by nebyl od věci přesně ze zníměných důvodů – především omezenosti INI formátu.
Ukládání bych určitě nerušil. To že se zruší uživatelské formátování a komentáře je samozřejmost a člověk s tím počítá. Neviděl bych to jako důvod k odstranění.
- Cifro
- Člen | 245
Tiež by som bol za pridanie načitavania viacerych configov. Aby sa to nemuselo obchadzať ako je to tu: /cs/2634-nacteni-vice-konfiguracnich-souboru
Editoval Cifro (27. 4. 2010 23:20)
- David Grudl
- Nette Core | 8227
YAML tak nějak nemám rád. Parsuje se složitě a bez nativního parseru i pomalu.
Možná tam dát nějaký liteYAML, tedy YAML s omezenou syntaxí a rychlým parserem.
- Honza Marek
- Člen | 1664
Co třeba JSON? Jeho použití by myslím hodně prospělo i config.ini souboru. JSON zachovává výhody ini souboru a má trochu širší možnosti, takže můžu mít třeba klíče jaké chci a navíc by mohla zmizet spousta další magie v config.ini souboru.
{
common: {
php: {
"date.timezone": "Europe/Prague",
"iconv.internal_encoding": "UTF-8",
"mbstring.internal_encoding": "UTF-8"
},
variable: {
lang: "en",
tempDir: "%appDir%/temp",
logDir: "%appDir%/log"
},
service: {
"Nette\\Security\\IAuthenticator": "UsersModel",
"Nette\\Loaders\\RobotLoader": {
option: {
directory: ["%appDir%", "%libsDir%"]
},
run: true
}
}
},
"production < common": {
database: {
host: "127.0.0.1",
//...
}
},
"development < common": {
}
}
Osobně se mi to hrozně líbí a přijde mi to o dost přehlednější než ini soubor.
- Petr Motejlek
- Člen | 293
Taky přidám svoji trošku ;).
Já jsem se zatím vždycky při konfigurování setkal s tím, že jsem si udělal třídu, která mi zajišťovala takovou vrstvu mezi aplikací a Nette\Config.
Dělal jsem to z toho důvodu, že mi přijde hezčí, když se na konfigurační volby ptám jako na atributy, které mi IDE dokáže napovídat (ať už pomocí @property, nebo čehokoliv jiného), než na stringy, ve kterých můžu udělat překlep. Druhý důvod byl takový, že si u třídy můžu nastavit, jaké jsou výchozí hodnoty u voleb, které nejsou vyplněné – tzn. nemusí se o výchozí hodnotu starat to, co si z konfigurace čte, ale sama ta konfigurace, a tím pádem všichni, kdo si z konfigurace čtou, vidí stejnou výchozí hodnotu.
Hezké mi taky přijde, že ta dědičnost, co Nette\Config do ini souborů zavedlo, se dá řešit i přes OOP. Konfigurace aplikace pak může vypadat tak, že namísto Environment::setName() a Environment::loadConfig() se bude volat něco jako Environment::loadConfig(Config $config = new NetteConfig()), s tím, že buď nepředám nic, a Nette si použije svoji výchozí třídu, nebo předám moji vlastní, která se použije.
Načítání samotných hodnot konfiguračních voleb by pak probíhalo normálním způsobem přes Environment::getConfig(‚hodnota‘) nebo Environment::getConfig()->hodnota, s tím, že Environment::getConfig() mi bude schopné vrátit tu instanci, takže s ní budu moct pracovat sám (hlavně si v IDE budu moct udělat /* @var MyConfig */ a bude mi to napovídat ;))
Načítání konfiguračních souborů by se teda vlastně delegovalo na require_once a instancování třídy ;).
P. S.: Nekamenujte mne, prosím, když s něcím výše nesouhlasíte. Nikomu to násilím nenutím, jen to sem vlepuji jako možný přístup.
- Honza Marek
- Člen | 1664
despiq napsal(a):
Ty uvozovky okolo dedicich zapisu jsou dost divny
bez dedeni pises bez uvozovek a pri dedeni s to je divny ne?
Pokud se v klíči vyskytují mezery a jiné divné znaky, tak tam ty uvozovky být musí. Jinak ne.
- David Grudl
- Nette Core | 8227
Nějaký takový jednoduchý formát by mi vyhovoval:
common:
php:
date.timezone: Europe/Prague
iconv.internal_encoding: UTF-8
mbstring.internal_encoding: UTF-8
variable:
name: František Dobrota :-) ; tohle je kometář
string: " delimited string \x0A "
tempDir: %appDir%/temp
logDir: %appDir%/log
service:
Nette\Security\IAuthenticator: UsersModel
Nette\Loaders\RobotLoader:
option:
directory: [%appDir%, %libsDir%]
run: TRUE
To by se dalo parsovat „jen“ asi jednou tak pomaleji než funguje současné řešení via INI. (Zkoušel jsem YAML parser ze Symfony a ten jen 20× pomalejší). Výhodou oproti INI je naprostá volnost pokud jde o používání znaků v klíčích a hodnotách.
Problém vidím v závádění další syntaxe, přitom hodně podobné YAMLu.
Případně ještě jednodušší alternativa pro zápis pole:
Nette\Loaders\RobotLoader:
option:
directory:
- %appDir%
- %libsDir%
run: TRUE
Při tomto zápisu by bylo výhodnější options
oproti
option
apod.
- Yrwein
- Člen | 45
David Grudl napsal(a):
YAML tak nějak nemám rád. Parsuje se složitě a bez nativního parseru i pomalu.
Možná tam dát nějaký liteYAML, tedy YAML s omezenou syntaxí a rychlým parserem.
http://components.symfony-project.org/yaml/
? ,)
- David Grudl
- Nette Core | 8227
Yrwein napsal(a):
Uvažoval jsem nad tím, ale je to pomalé. Pro mírně jednodušší syntax dovedu napsat 10× rychlejší parser. Otázka je, zda-li je lepší kešovat, nebo zavádět novou syntax.
- pekelnik
- Člen | 462
Zavádění další syntaxe bych se vyhnul. Syntaxí je i tak spousta – proč pro konfiguraci další?
Imho je lepší kešovat než zavádět novou syntax.
Když se na to člověk podívá selským rozumem: Proč parsovat (byť seberychlejším parserem) něco co se vůbec nemění?
Mimoto YAML má spoustu fičur, které z něj dělají daleko silnější nástroj. Např. reference nebo aliasy.
- Honza Kuchař
- Člen | 1662
Honza Marek napsal(a):
despiq napsal(a):
Ty uvozovky okolo dedicich zapisu jsou dost divny
bez dedeni pises bez uvozovek a pri dedeni s to je divny ne?Pokud se v klíči vyskytují mezery a jiné divné znaky, tak tam ty uvozovky být musí. Jinak ne.
Pokud by sis to nechtěl pamatovat, tak bys je mohl psát všude. :-)
- Tharos
- Člen | 1030
Honza Marek napsal(a):
despiq napsal(a):
Ty uvozovky okolo dedicich zapisu jsou dost divny
bez dedeni pises bez uvozovek a pri dedeni s to je divny ne?Pokud se v klíči vyskytují mezery a jiné divné znaky, tak tam ty uvozovky být musí. Jinak ne.
Pozor, v případě JSONu by tam ale ty uvozovky měly být vždycky, viz například zdejší pojednání. Bez nich ten JSON skutečně neprojde žádným validátorem (například JSONLintem, JSON Formatterem…).
- Tharos
- Člen | 1030
Mně se JSON taky líbí, ale právě bez těch uvozovek. S těmi uvozovkami mi přijde takovej zbytečně ukecanej a technickej… Každopádně to, že by konfigurační soubor měl syntaxi nevalidního JSONu, by bylo asi to nejblbější, co by šlo udělat :(.
Editoval Tharos (29. 4. 2010 14:15)
- Petr Motejlek
- Člen | 293
wotaen napsal(a):
A nešlo by to prostě mít pár tříd, CommonConfiguration, ProductionConfiguration atd., které by měly proměnnou $config (pole), která by se dala přepisovat podle potřeby dědičností?
Sice to nebude tak hezké napohled, ale hlavně odpadne parsování a bude to rychlejší.
To mě přijde neskutečně ohyzdné, když už třídy, tak s atributy… ;) Viz výše.
- wotaen
- Člen | 82
Petr Motejlek napsal(a):
wotaen napsal(a):
A nešlo by to prostě mít pár tříd, CommonConfiguration, ProductionConfiguration atd., které by měly proměnnou $config (pole), která by se dala přepisovat podle potřeby dědičností?
Sice to nebude tak hezké napohled, ale hlavně odpadne parsování a bude to rychlejší.To mě přijde neskutečně ohyzdné, když už třídy, tak s atributy… ;) Viz výše.
Pravda, to jsem nečetl…už jo a líbí se mi to…nebude potřeba žádný
parser, řešit nový formát, atd, prostě nic. Stejně se ve většině
případů config jednou vytvoří a pak se do něj nešahá…
JSON je fajn, ale jenom do chvíle než to má víc jak tři vnořené úrovně,
pak se mi z těch závorek točí hlava (to, že IDE umí naznačit párovou
závorku moc nepomůže ve chvíli, kdy je mimo obrazovku)
S YAML jsem nikdy (aktivně) nedělal, tak nemůžu soudit
- arron
- Člen | 464
Vsechno je to hrozne hezky, ale ackoliv je INI lehce omezene nekterymi drobnostmi, co je na nem ve skutecnosti tak spatneho, ze by bylo treba ho vymenit? Krom toho ho osobne povazuju za pomerne standardni format pro konfiguracni soubory. Opravdu potrebujeme v konfiguraci delat takove vylomeniny, ze nutne potrebujeme jiny format?
Neberte to jako dogma, ale do ted to pomerne slusne fungovalo a opravdu by me zajimal nejaky opravdu vazny duvod, proc INI vymenit. Obzvlast, pokud zustane zachovany system adapteru (jeste jsem ten commit moc neprolejzal…), tak si ev. kazdy muze napsat co jemu libo:-)
- David Grudl
- Nette Core | 8227
Zvážil jsem všechna pro a proti a vidím to takto:
- INI je nedostatečný formát. Už teď se kvůli němu dělá řada ústupků a nad vestavěným parserem musí existovat nádstavba, která vytváří pole podle tečky a implementuje dědičnost. Rád bych jej nahradil.
- JSON a XML jsou pro konfiguraci formáty nevhodné z důvodu velké ukecanosti (no flame please)
- YAML je formát pro konfigurační soubory nejvhodnější. Výhodou je, že jde de-facto o standard, existují pro něj (nenativní) parsery pro PHP a také třeba validátor. Jeho syntax je na potřeby INI souboru zbytečně bohatá, ale to nevadí. Zamrzí nemožnost používat tabulátory a pomalost PHP parserů.
- Vlastní formát likeYAML nebo liteYAML by mohl eliminovat všechny zmíněné nevýhody YAMLu. Nevýhodou je zavádění dalšího formátu. Tento by totiž asi nemohl být čistě subsetem YAMLu, právě třeba kvůli podpoře tabulátorů.
- Realita je ovšem taková, že Nette už řadu DSL
zavádí a je tu akutní potřeba dalšího DSL pro anotace. Zde je
standardem Java a přijal jej například Doctrine. DSL anotací je hodně odlišené od inline YAML
(
{}
versus[]
, znak=
versus:
).
Závěr? Vytvořím pro konfiguráky a anotace syntax, která bude jednotná. Zároveň bude možné napsat konfigurák tak, aby to byl platný dokument i v YAML.
Verze 1.0 nebude vůbec používat INI. Přidám jednoduchý konvertor z INI do nového formátu. Název nového formátu je úkolem pro paranoiqa :-)
- David Grudl
- Nette Core | 8227
Nová syntax bude podporovat zápis:
- pole:
{"Alice", "Bob", "Cindy"}
a["Alice", "Bob", "Cindy"]
- hash:
{hr: 65, avg: 0.278}
a{hr = 65, avg = 0.278}
a{hr => 65, avg => 0.278}
(také{'hr': 65, 'avg': 0.278}
) - boolean: true | false | yes | no
- čísla:
-10.5
- řetězce:
"word"
'word'
"word\x0A\u000A"
nebo jakýkoliv tok znaků neobsahující!"#$&'()*+,-/:;<=>?@[]^{|}
a whitespace (v případě blokového zápisu budou pravidla volnější) - komentáře:
# comment
- objekt:
@name(type="string", length=32,)
A zároveň blokový zápis:
common:
php:
date.timezone: Europe/Prague
iconv.internal_encoding: UTF-8
mbstring.internal_encoding: UTF-8
american:
- Boston Red Sox
- Detroit Tigers
- New York Yankees
- buff
- Člen | 63
JSON a XML jsou pro konfiguraci formáty nevhodné z důvodu velké ukecanosti (no flame please)
Tohle bez flamu nepůjde :-) JSON že je ukecanější než YAML? (O XML není řeči.)
A určitě je třeba zavádět novou syntax? Neposlouží i pro jednotnou syntax nějaký již standardizovaný formát? Nezavře si Nette novými formáty cestu k interoperabilitě s externími nástroji?
- Mikulas Dite
- Člen | 756
Bude odsazování hrát svojí roli, nebo je jenom pro zpřehlednění?
Tzn. je něco jiného tohle?
common:
php:
date.timezone: Europe/Prague
common:
php:
date.timezone: Europe/Prague
- David Grudl
- Nette Core | 8227
buff napsal(a):
Tohle bez flamu nepůjde :-) JSON že je ukecanější než YAML? (O XML není řeči.)
Tak srovnej: YAML
name: František Dobrota
age: 32
JSON
{"name": "František Dobrota",
"age": 32}
- Honza Marek
- Člen | 1664
David Grudl napsal(a):
- hash:
{hr: 65, avg: 0.278}
a{hr = 65, avg = 0.278}
a{hr => 65, avg => 0.278}
(také{'hr': 65, 'avg': 0.278}
)
Proč se dá jedna věc napsat deseti způsobama? Nebylo by lepší říct, že chceme třeba dvojtečky a = a ⇒ ne?
- David Grudl
- Nette Core | 8227
Honza Marek napsal(a):
Proč se dá jedna věc napsat deseti způsobama? Nebylo by lepší říct, že chceme třeba dvojtečky a = a ⇒ ne?
Tady je vysvětleno vše. (bod 5)
- David Grudl
- Nette Core | 8227
David Grudl napsal(a):
Honza Marek napsal(a):
Proč se dá jedna věc napsat deseti způsobama? Nebylo by lepší říct, že chceme třeba dvojtečky a = a ⇒ ne?Tady je vysvětleno vše. (bod 5)
Teď si uvědomuju, že jsem to možná nepochopil. Chtěl bych mít jednotný parser, který si poradí se všemi oddělovači, nicméně pro konkrétní kontext by byl předepsán právě jeden oddělovač.
- David Grudl
- Nette Core | 8227
paranoiq napsal(a):
Davide, ve tvé ‚specifikaci‘ nikde nevidím tečkovou syntax (krom příkladu), konstanty a dědičnost. jak bude pořešeno tohle?
Tečková syntax je hack na INI soubory který komplikuje situace, kdy
skutečně je potřeba v identifikátoru tečka. Vhodnější než nějaké
uvozovkování common.php."date.timezone": Europe/Prague
mi přijde
prostě využít YAML formát, takže z původního
[common]
php.date.timezone: Europe/Prague
php.iconv.internal_encoding: UTF-8
php.mbstring.internal_encoding: UTF-8
na
common:
php:
date.timezone: Europe/Prague
iconv.internal_encoding: UTF-8
mbstring.internal_encoding: UTF-8
Konstanty myslíš jako třeba?
variable.name = USER_NAME
To bych asi nechal na post-processing, aby bylo načítání souboru
nezávislé na prostředí (což fakticky vedlo kdysi dávno ke zrušení
kešování konfigurace) a stejně tak i dědičnost. Protože klíče
v konfigu mohou mít mezery a znak <
, není problém:
development < common:
php:
date.timezone: Europe/Paris