Slučování konfigurací
Aplikace často skládají konfiguraci z více vrstev: vestavěných výchozích hodnot, konfiguračního souboru sdíleného týmem a lokálního souboru každého vývojáře. Každá vrstva přepíše jen ty položky, které uvádí. Tato stránka ukazuje:
- jak
processMultiple()vrstvy sloučí a výsledek zvaliduje - jak se kombinují struktury, pole a listy
- jak zvolit jinou strategii pomocí
mergeMode()nebo vlastní funkce - jak se slučují pole, jejichž položky nejsou popsané
Ukázky navazují na konfiguraci aplikace z úvodu. $processor je
instance Nette\Schema\Processor.
Slučování vrstev: processMultiple()
Metoda processMultiple() vezme několik datových sad, sloučí je v pořadí tak, že pozdější mají
přednost, a výsledek zvaliduje jako celek:
$schema = Expect::structure([
'host' => Expect::string(),
'port' => Expect::int(),
'logging' => Expect::bool(),
]);
$defaults = ['host' => 'localhost', 'port' => 3306, 'logging' => false];
$local = ['port' => 5432, 'logging' => true];
$config = $processor->processMultiple($schema, [$defaults, $local]);
// $config = {'host' => 'localhost', 'port' => 5432, 'logging' => true}
Položka host si ponechá výchozí hodnotu, protože ji lokální soubor nenastavil, zatímco port a
logging přepíše pozdější datová sada.
Všimněte si, že se výsledek validuje jen jednou, až po sloučení. Samotná vrstva může být neúplná, třeba výchozí hodnotám obvykle chybí heslo, a všechno povinné musí obsahovat až sloučená konfigurace.
Jak se hodnoty kombinují
O tom, jak se dvě vrstvy zkombinují, rozhoduje schéma:
- jednoduchou hodnotu, třeba řetězec nebo číslo, nahradí ta pozdější
- struktura a pole s řetězcovými klíči se slučují podle klíčů, rekurzivně podle schémat svých položek
- položky listu (
listOf(), případněarrayOf()s číselnými klíči) se připojují jedna za druhou - tuple se nahradí celý, protože smíchat pozice dvou tuplů by dalo jen nesmysl
Takže s 'admins' => Expect::listOf('email') se správci z lokálního souboru přidají k těm ze
sdíleného:
$schema = Expect::structure([
'admins' => Expect::listOf('email'),
]);
$config = $processor->processMultiple($schema, [
['admins' => ['jim@example.com']],
['admins' => ['ann@example.com']],
]);
// $config->admins = ['jim@example.com', 'ann@example.com']
Výchozí hodnota pole se s vrstvami také slučuje: její položky zůstanou, pokud je některá vrstva nepřepíše, a k listu se položky vrstev připojí. Pokud to nechcete, zavolejte mergeDefaults(false).
Volba strategie: mergeMode()
Pokud připojování nebo slučování podle klíčů není to, co chcete, mohou si pole a struktury zvolit jinou strategii
metodou mergeMode(). Dejme tomu, že lokální soubor má seznam správců nahradit, ne k němu přidávat:
use Nette\Schema\MergeMode;
Expect::listOf('email')->mergeMode(MergeMode::Replace); // pozdější list nahradí ten dřívější
MergeMode::AppendKeys slučuje podle klíčů a položky listu připojuje, OverwriteKeys také
slučuje podle klíčů, ale položky listu přepisuje podle jejich pozice, a Replace ponechá jen pozdější
hodnotu.
V konfiguračním souboru NEON aplikace Nette zabrání vykřičník za klíčem, admins!:, sloučení té jedné
položky, viz konfigurace DI
kontejneru.
Pole bez popsaných položek
Pole, jehož položky nejsou popsané, třeba Expect::array(), se slučuje do hloubky, podle klíčů na všech
úrovních:
$schema = Expect::structure([
'options' => Expect::array(),
]);
$processor->processMultiple($schema, [
['options' => ['cache' => ['ttl' => 60]]],
['options' => ['cache' => ['ttl' => 3600]]],
]);
// OK, vrátí {'options' => ['cache' => ['ttl' => 3600]]}
Počítejte s tím, že schéma pak nemůže zkontrolovat, co pole obsahují. Pokud má pozdější vrstva pole nahradit
celé, zvolte mergeMode(MergeMode::Replace).
Vlastní funkce: mergeWith()
Pro cokoliv jiného je tu mergeWith(), kterému předáte vlastní funkci, jež pozdější hodnotu zkombinuje
s tou dřívější. Dejme tomu, že logování má zůstat zapnuté, jakmile ho kterákoliv vrstva zapne:
Expect::bool()->mergeWith(fn($value, $base) => $value || $base); // jednou zapnuto, zůstane zapnuto
Funkce jen kombinuje vrstvy; pokud chcete upravit tvar jedné vrstvy, použijte before().