Version 3.0

Schema

Praktická knihovna pro validaci datových struktur proti danému schématu.

$processor = new Nette\Schema\Processor;

try {
    $normalized = $processor->process($schema, $data);
} catch (Nette\Schema\ValidationException $e) {
    echo 'Data nejsou platná: ' . $e->getMessage();
}

// v případě chyby vyhodí Nette\Schema\ValidationException

Definování schématu

use Nette\Schema\Expect;

$schema = Expect::structure([
    'processRefund' => Expect::bool(),
    'refundAmount' => Expect::int(),
]);

$data = [
    'processRefund' => true,
    'refundAmount' => 17,
];

$normalized = $processor->process($schema, $data); // projde!

Pokud ověření dat projde, můžete přetypovat řetězce a logické hodnoty na očekávané typy definované vaším schématem:

$schema = Expect::structure([
    'processRefund' => Expect::scalar()->castTo('bool'),
    'refundAmount' => Expect::scalar()->castTo('int'),
]);

$data = [
    'processRefund' => 1,
    'refundAmount' => '17',
];

$normalized = $processor->process($schema, $data); // projde!

is_bool($normalized->processRefund); // true
is_int($normalized->refundAmount); // true

Ve výchozím nastavení jsou všechny prvky volitelné a mají výchozí hodnotu null, nebo [] v případě polí.

Výchozí hodnotu můžete změnit tímto způsobem:

$schema = Expect::structure([
    'processRefund' => Expect::bool()->default(true), // or Expect::bool(true)
]);

$data = [];

// ověřuje a nastavuje výchozí hodnoty pro chybějící prvky
$normalized = $processor->process($schema, $data);

// $normalized->processRefund === true;

Položky pole

Pole, kde jsou povoleny prvky pouze řetězce:

$schema = Expect::arrayOf('string');

$processor->process($schema, ['key1' => 'a', 'key2' => 'b']); // projde
$processor->process($schema, ['key' => 123]); // chyba: The option 'key' expects to be string, int 123 given.

Indexované pole pouze s číselnými klíči:

$schema = Expect::listOf('string');

$processor->process($schema, ['a', 'b']); // projde
$processor->process($schema, ['key' => 'a']); // error, unexpected 'key'

Výčtové hodnoty a anyOf()

anyOf() se používá k omezení hodnoty na pevnou sadu variant nebo podschémat:

$schema = Expect::listOf(
    Expect::anyOf('a', true, null)
);

$processor->process($schema, ['a', true, null, 'a']); // projde
$processor->process($schema, ['a', false]); // chyba: The option '1' expects to be 'a'|true|null, false given.

Prvky mohou být schémata:

$schema = Expect::listOf(
    Expect::anyOf(Expect::string(), true, null)
);

$processor->process($schema, ['foo', true, null, 'bar']); // projde
$processor->process($schema, [123]); // chyba: The option '0' expects to be string|true|null, 123 given.

Struktury

Struktury jsou objekty s definovanými klíči. Každá z dvojic klíč ⇒ hodnota je označována jako „vlastnost“:

Ve výchozím nastavení jsou všechny vlastnosti volitelné a mají výchozí hodnotu null. Povinné vlastnosti můžete definovat pomocí required():

$schema = Expect::structure([
    'required' => Expect::string()->required(),
    'optional' => Expect::string(), // výchozí hodnota je null
]);

$processor->process($schema, ['optional' => '']); // chyba: option 'required' is missing
$processor->process($schema, ['required' => 'foo']); // projde, returns (object) ['required' => 'foo', 'optional' => null]

Vlastnosti akceptující hodnotu null můžete definovat pomocí nullable():

$schema = Expect::structure([
    'optional' => Expect::string(),
    'nullable' => Expect::string()->nullable(),
]);

$processor->process($schema, ['optional' => null]); // chyba: 'optional' expects to be string, null given.
$processor->process($schema, ['nullable' => null]); // projde, returns (object) ['optional' => null, 'nullable' => null]

Ve výchozím nastavení je zakázáno uvádět další vlastnosti:

$schema = Expect::structure([
    'key' => Expect::string(),
]);

$processor->process($schema, ['additional' => 1]); // chyba: Unexpected option 'additional'

otherItems() se používá ke kontrole dalších prvků, tj. vlastností, které nejsou uvedeny v Expect::structure():

$schema = Expect::structure([
    'key' => Expect::string(),
])->otherItems(Expect::int());

$processor->process($schema, ['additional' => 1]); // projde

Velikost a rozsahy

Počet prvků lze omezit pomocí min() a max():

// pole, nejméně 10 položek, maximálně 20 položek
$schema = Expect::array()->min(10)->max(20);

Délka řetězce může být omezena pomocí min() a max():

// řetězec, nejméně 10 znaků dlouhý, maximálně 20 znaků
$schema = Expect::string()->min(10)->max(20);

Rozsah čísel lze omezit pomocí min() a max():

// celé číslo, mezi 10 a 20
$schema = Expect::int()->min(10)->max(20);

Mapování dat na objekty

Schéma může být generována ze třídy:

class Config
{
    /** @var string */
    public $dsn;

    /** @var string|null */
    public $user;

    /** @var string|null */
    public $password;

    /** @var bool */
    public $debugger = true;
}

$schema = Expect::from(new Config);

$data = [
    'dsn' => 'sqlite',
    'user' => 'root'
];

$normalized = $processor->process($schema, $data);
// $normalized is Config class
// $normalized->dsn === 'sqlite'
// $normalized->user === 'root'
// $normalized->password === null
// $normalized->debugger === true

Můžete dokonce použít zápis PHP 7.4:

class Config
{
    public string $dsn;
    public ?string $user;
    public ?string $password;
    public bool $debugger = true;
}

$schema = Expect::from(new Config);

Nebo použijte anonymní třídu:

$schema = Expect::from(new class {
    public string $dsn;
    public ?string $user;
    public ?string $password;
    public bool $debugger = true;
});

Vlastní normalizace

$schema = Expect::arrayOf('string')
    ->before(function ($v) { return explode(' ', $v); });

$normalized = $processor->process($schema, 'a b c'); // projde a vrátí ['a', 'b', 'c']

Vlastní omezení

$schema = Expect::arrayOf('string')
    ->assert(function ($v) { return count($v) % 2 === 0; }); // počet musí být sudý

$processor->process($schema, ['a', 'b']); // projde, 2 je sudé číslo
$processor->process($schema, ['a', 'b', 'c']); // chyba, 3 není sudé číslo