Změny v Nette\Config pro verzi 2.0

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

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
+
0
-

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.

bazo
Člen | 620
+
0
-

ja pouzivam ukladanie do ini suboru na ulozenie uzivatelskej konfiguracie napr. nastavenie tem, master hesla atd. rozhodne je to uzitocne. takze nerusit, skor vylepsit

David Grudl
Nette Core | 8227
+
0
-

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
+
0
-

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?

bazo
Člen | 620
+
0
-

myslim, ze ked importujes iba nejaku sekciu configu, zmenis nieco, das ulozit, ostatne sekcie uz vo vygenerovanom subore nie su. ale je to uz trochu dlhsie co som toto riesil.

Honza Marek
Člen | 1664
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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í.

Majkl578
Moderator | 1364
+
0
-

David Grudl napsal(a):

nemůže být uvozovka

Může, ale krkolomně:

var_dump(parse_ini_file('/tmp/foo.ini'));
foo = abcd
bar = "ef\"gh"
baz = ij'kl
array
  'foo' => string 'abcd' (length=4)
  'bar' => string 'ef"gh' (length=5)
  'baz' => string 'ij' (length=2)
Cifro
Člen | 245
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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.

despiq
Člen | 320
+
0
-

Ty uvozovky okolo dedicich zapisu jsou dost divny
bez dedeni pises bez uvozovek a pri dedeni s to je divny ne?

prehledny to je o tom zadna ale to vyse mi prijde zvlastni

Honza Marek napsal(a):

Co třeba JSON?

Honza Marek
Člen | 1664
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Yrwein napsal(a):

http://components.symfony-project.org/yaml/

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.

despiq
Člen | 320
+
0
-

ja bych zavedl novou syntax, to je muj sobecky postoj
kdyz ale kouknu na nove prichozi pak je to uceni se navic ktere muze odradit

Honza Kuchař
Člen | 1662
+
0
-

Teď mně tak napadlo… JSON?

despiq
Člen | 320
+
0
-

to uz psal H.Marek

honzakuchar napsal(a):

Teď mně tak napadlo… JSON?

pekelnik
Člen | 462
+
0
-

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.

buff
Člen | 63
+
0
-

Zavádění další syntaxe bych se vyhnul. Syntaxí je i tak spousta – proč pro konfiguraci další?

+1

Honza Kuchař
Člen | 1662
+
0
-

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. :-)

despiq
Člen | 320
+
0
-

a jak je rychly parsovani JSONu?

Tharos
Člen | 1030
+
0
-

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…).

Honza Kuchař
Člen | 1662
+
0
-

Máš recht. http://www.json.org/

Editoval honzakuchar (29. 4. 2010 14:02)

Tharos
Člen | 1030
+
0
-

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)

pekelnik
Člen | 462
+
0
-

Svůj předchozí názor jsem si rozmyslel.

Vlastní syntax ve stylu zjednodušeného YAMLu by nebyla na škodu.

Zvláště pokud by šlo odsazovat pomocí tabů. :)

wotaen
Člen | 82
+
0
-

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ší.

Honza Marek
Člen | 1664
+
0
-

Jo tak to je škoda.

Petr Motejlek
Člen | 293
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Zvážil jsem všechna pro a proti a vidím to takto:

  1. 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.
  2. JSON a XML jsou pro konfiguraci formáty nevhodné z důvodu velké ukecanosti (no flame please)
  3. 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ů.
  4. 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ů.
  5. 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
+
0
-

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
+
0
-

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?

hrach
Člen | 1838
+
0
-

@David Grudl: dalsi texy? :D

Mikulas Dite
Člen | 756
+
0
-

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
+
0
-

Ano, bude to hrát stejnou roli jako třeba v Pythonu.

David Grudl
Nette Core | 8227
+
0
-

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}
pekelnik
Člen | 462
+
0
-

Heh :) tak to jsem nečekal.

Jsem nadšen :)

Honza Marek
Člen | 1664
+
0
-

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?

Majkl578
Moderator | 1364
+
0
-

Honza Marek napsal(a):

David Grudl 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?

Souhlasím.
<ot>Totéž se mi nezamlouvá u makra var LatteFilteru.</ot>

David Grudl
Nette Core | 8227
+
0
-

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)

paranoiq
Člen | 392
+
0
-

Davide, ve tvé ‚specifikaci‘ nikde nevidím tečkovou syntax (krom příkladu), konstanty a dědičnost. jak bude pořešeno tohle?

Editoval paranoiq (30. 4. 2010 9:07)

David Grudl
Nette Core | 8227
+
0
-

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
+
0
-

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