Novinky v Nette Schema 1.2
Nette Schema je nejmladší přírůstek do Nette rodiny. Knihovna vznikla původně pro potřeby Nette DI, tedy kvůli validaci a normalizaci vstupních konfiguračních souborů a informování o případných chybách.
Nette Schema se pokusilo najít srozumitelný a úsporný jazyk pro popis datových struktur. První verze pokrývala veškeré potřeby Nette DI a další vývoj pak řeší požadavky vzešlé od nových uživatelů a nasazení.
Připomeňme si, jak se vlastně Schema používá. Vytvoříme
například schéma, kde vstup má být pole (či objekt s public properties,
v terminologii Schema jde o strukturu), s povinným prvkem foo
typu bool
a nepovinným číselným bar
a řetězcem
baz
:
use Nette\Schema\Expect;
$schema = Expect::structure([
'foo' => Expect::bool()->required(),
'bar' => Expect::int()->default(123),
'baz' => Expect::string(),
]);
A validujeme vstupní $data
:
$processor = new Nette\Schema\Processor;
$normalized = $processor->process($schema, $data);
// v případě chyby vyhodí Nette\Schema\ValidationException
Uvnitř structure()
platí, že pokud neuvedeme jinak, tak
každý prvek:
- je nepovinný
- má výchozí hodnotou
null
(resp.[]
v případě polí)
Že má výchozí hodnotu null
neznamená, že null
také akceptuje – to by ve schématu by muselo být uvedeno např.
Expect::int()->nullable()
.
Takže pro vstup $data = ['foo' => true]
vrátí objekt
{foo: true, bar: 123, baz: null}
, viz demo. Tedy můžeme si
sáhnout na $normalized->bar
bez obav, že by property nebyla
definovaná.
Výchozí hodnoty struktury
Pokud prvek akceptuje null
a zároveň má výchozí hodnotu
null
, nelze odlišit výchozí hodnotu od předané. Pokud je to
potřeba, lze od verze 1.2 výchozí hodnoty zcela vypnout pomocí
skipDefaults()
:
$schema = Expect::structure([
...
])->skipDefaults();
Takže pro vstup $data = ['foo' => true]
vrátí objekt
{foo: true}
.
Povinné/nepovinné prvky
Jak bylo řečeno, povinné jsou jen prvky označené jako
required()
. Co ale pokud je struktura hlubší? Je prvek
bar
povinný?
$schema = Expect::structure([
'foo' => Expect::int(),
'inner' => Expect::structure([
'bar' => Expect::string()->required(),
]),
]);
Schema se v tomto případě snaží chovat tak, aby nezaskočilo
programátora, takže prvek bar
povinný je, byť striktně
technicky by musel být i prvek inner
označen za povinný. Schema
ho učiní povinným implicitně. Viz demo.
Nyní lze označit strukturu za skutečně nepovinnou pomocí
requred(false)
.
$schema = Expect::structure([
'foo' => Expect::int(),
'inner' => Expect::structure([
'bar' => Expect::string()->required(),
])->required(false),
]);
V takovém případě data nemusí obsahovat klíč inner
,
pokud ho však obsahují, musí být přítomen i podklíč
bar
.
Spojování prvků v polích
Jednou z věcí, která vzešla z chování Nette DI, ale pro uživatele
samostatného Schema se ukázala jako překvapivá, bylo mergování výchozích
a předaných hodnot v případě polí, tj. třeba
Expect::array()
, list()
apod. Ve verzi Nette Schema
2 bude toto chování odstraněno, nyní jej lze vypnout:
Expect::list([1, 2, 3])->mergeDefaults(false)
arrayOf() a klíč
arrayOf
říká, jaké prvky může obsahovat pole. Například
pole, jehož prvky mohou být pouze řetězce, zapíšeme jako
Expect::arrayOf('string')
.
Nově lze specifikovat i typ klíče druhým parametrem:
$schema = Expect::arrayOf('string', 'int');
Výchozí hodnota anyOf()
Nyní lze snadněji definovat výchozí hodnotu výčtu anyOf()
tím, že za výchozí prohlásíme první položku:
Expect::anyOf(
Expect::string()->default('def'),
false,
)->firstIsDefault();
Výchozí hodnota takového prvku je 'def'
.
Bohatší chybové hlášky
V případě, že data neprojdou validací, vyhodí se výjimka Nette\Schema\ValidationException.
Její metoda getMessages()
vrací pole všech
chybových zpráv.
Novinkou je metoda getMessageObjects()
, která vrací pole chyb
jakožto objektů Nette\Schema\Message.
V nich je zpráva rozložená na základní informace:
$messages = $e->getMessageObjects();
$message = $messages[0];
$message->message // text zprávy s %placeholdery% pro proměnné
$message->code // kód chyby, jedna z konstant v třídě Message
$message->path // pole odkazující na prvek kterého se chyba týká
$message->variables // proměnné, které nahradí %placeholdery%
Díky tomu lze snadno zprávy třeba překládat do jiných jazyků.
Deprecated
A na závěr: prvky lze označovat jako deprecated s volitelnou chybovou
hláškou. Seznam varování pak vrací getWarnings()
.
use Nette\Schema\Expect;
$schema = Expect::structure([
'foo' => Expect::bool()->deprecated('Použijte místo toho `bar`'),
'bar' => Expect::bool(),
]);
$normalized = $processor->process($schema, $data);
$warnings = $processor->getWarnings(); // vrací pole řetězců
Chcete-li odeslat komentář, přihlaste se