Skip to content
πŸ“ Validating data structures against a given Schema.
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github Lets start Apr 3, 2019
src/Schema Added support for pattern() (#6) Jul 11, 2019
tests Added support for pattern() (#6) Jul 11, 2019
.gitattributes Lets start Apr 3, 2019
.gitignore init Mar 27, 2019
.travis.yml Lets start Apr 3, 2019
composer.json Lets start Apr 3, 2019
contributing.md Lets start Apr 3, 2019
license.md
readme.md Added support for pattern() (#6) Jul 11, 2019

readme.md

Nette Schema


Downloads this Month Build Status Coverage Status Latest Stable Version License

Introduction

Handy library for validating data structures against a given Schema.

Documentation can be found on the website.

If you like Nette, please make a donation now. Thank you!

Installation

The recommended way to install is via Composer:

composer require nette/schema

It requires PHP version 7.1 and supports PHP up to 7.4.

Usage

$processor = new Nette\Schema\Processor;

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

// in case of error it throws Nette\Schema\ValidationException

Defining schema

use Nette\Schema\Expect;

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

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

$normalized = $processor->process($schema, $data); // it passes

If you're validating data passed, you can cast strings and booleans to the expected types defined by your schema:

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

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

$normalized = $processor->process($schema, $data); // it passes

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

By default, all properties are optional and have default value null, or [] in the case of arrays.

You can change the default value as follows:

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

$data = [];

// validates, and sets defaults for missing properties
$normalized = $processor->process($schema, $data);

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

Arrays of items

Array where only string items are allowed:

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

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

Indexed array (ie. with numeric keys) where only string items are allowed:

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

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

Enumerated values and anyOf()

The anyOf() is used to restrict a value to a fixed set of variants or subschemes:

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

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

Elements can be schema:

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

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

Structures

Structures are objects with defined keys. Each of these key => pairs is conventionally referred to as a β€œproperty”.

By default, all properties are optional and have default value null. You can define mandatory properties via required():

$schema = Expect::structure([
	'required' => Expect::string()->required(),
	'optional' => Expect::string(), // default is null
]);

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

You can define nullable properties via nullable():

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

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

By default, providing additional properties is forbidden:

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

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

The otherItems() is used to control the handling of extra stuff, that is, properties whose names are not listed in Expect::structure():

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

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

Size and ranges

You can limit the number of elements or properties using the min() and max():

// array, at least 10 items, maximum 20 items
$schema = Expect::array()->min(10)->max(20);

The length of a string can be constrained using the min() and max():

// string, at least 10 characters long, maximum 20 characters
$schema = Expect::string()->min(10)->max(20);

Ranges of numbers are specified using a combination of min() and max():

// integer, between 10 and 20
$schema = Expect::int()->min(10)->max(20);

Regular expressions

String can be restricted by regular expression using the pattern():

// just 9 numbers
$schema = Expect::string()->pattern('\d{9}');

Data mapping to objects

Schema can be generated from class:

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

You can even use PHP 7.4 notation:

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

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

Or use anonymous class:

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

Custom normalization

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

$normalized = $processor->process($schema, 'a b c'); // it passes and returns ['a', 'b', 'c']

Custom constraints

$schema = Expect::arrayOf('string')
	->assert(function ($v) { return count($v) % 2 === 0; }); // count must be even number

$processor->process($schema, ['a', 'b']); // it passes, 2 is even number
$processor->process($schema, ['a', 'b', 'c']); // error, 3 is not even number
You can’t perform that action at this time.