| name | nette-schema |
| description | Provides Nette Schema for data validation and normalization. Use when validating configuration, API inputs, or any data structures with Expect class. Covers Expect::structure(), Expect::from(), anyOf, arrayOf, listOf, assert, transform, castTo, otherItems, and Processor. This is about nette/schema – not Nette Forms validation (addRule), not Nette\Utils\Validators, and not JSON Schema. |
Nette Schema
A library for validating and normalizing data structures against a defined schema. Declare what correct data looks like, and Schema verifies and transforms input in one step.
composer require nette/schema
When to Use Schema
- Configuration validation – validate config arrays loaded from .neon files
- API input validation – validate request data before processing
- Data import/transform – normalize external data into typed structures
- DI extension config – validate extension configuration in
loadConfiguration()
Schema is complementary to Nette Forms (which handles user input with UI) and database constraints (which enforce storage-level rules). Use Schema for programmatic data validation where there's no form UI.
Basic Usage
use Nette\Schema\Expect;
use Nette\Schema\Processor;
$schema = Expect::structure([
'name' => Expect::string()->required(),
'email' => Expect::email(),
'age' => Expect::int()->min(0)->max(120),
]);
$processor = new Processor;
try {
$normalized = $processor->process($schema, $data);
} catch (Nette\Schema\ValidationException $e) {
echo 'Invalid: ' . $e->getMessage();
}
Data Types
Expect::string()
Expect::string('default')
Expect::int()
Expect::float()
Expect::bool()
Expect::null()
Expect::array()
Expect::scalar()
Expect::type('ClassName')
Expect::type('bool|string')
Arrays
Expect::arrayOf('string')
Expect::arrayOf(Expect::string())
Expect::arrayOf('string', 'string')
Expect::listOf('string')
Expect::array([
Expect::int(),
Expect::string(),
Expect::bool(),
])
Structures
$schema = Expect::structure([
'database' => Expect::structure([
'host' => Expect::string()->required(),
'port' => Expect::int(3306),
'user' => Expect::string()->required(),
'password' => Expect::string()->nullable(),
]),
'debug' => Expect::bool(false),
]);
Properties are optional by default (null). Use required() for mandatory fields.
Enumeration
Expect::anyOf('small', 'medium', 'large')
Expect::anyOf(
Expect::string(),
Expect::int(),
null
)
Expect::anyOf('small', 'medium', 'large')->firstIsDefault()
Constraints
Expect::string()->required()
Expect::string()->nullable()
Expect::string()->default('hello')
Expect::string('hello')
Expect::string()->min(3)->max(100)
Expect::array()->min(1)->max(10)
Expect::int()->min(0)->max(100)
Expect::string()->pattern('\d{5}')
Assertions
Expect::string()->assert(fn($s) => strlen($s) % 2 === 0, 'Must be even length')
Expect::string()->assert('is_file')
Expect::string()->assert('ctype_alpha')
Transformations
Expect::string()->transform(fn($s) => strtoupper($s))
Expect::string()
->assert('ctype_lower', 'Must be lowercase')
->transform(fn($s) => strtoupper($s))
Expect::string()->transform(function ($s, $context) {
if (!ctype_alpha($s)) {
$context->addError('Must be letters only');
return null;
}
return strtoupper($s);
})
Casting
Expect::scalar()->castTo('string')
Expect::scalar()->castTo('int')
Expect::scalar()->castTo('bool')
Expect::structure([
'name' => Expect::string(),
'age' => Expect::int(),
])->castTo(Person::class)
Expect::structure([
'host' => Expect::string(),
'port' => Expect::int(),
])->castTo(DatabaseConfig::class)
Normalization (before)
Expect::arrayOf('string')
->before(fn($v) => is_string($v) ? explode(' ', $v) : $v)
Structure Options
Expect::structure([
'known' => Expect::string(),
])->otherItems(Expect::mixed())
Expect::structure([
'debug' => Expect::bool(false),
])->skipDefaults()
$base = Expect::structure(['name' => Expect::string()]);
$extended = $base->extend(['email' => Expect::email()]);
From Class
Generate schema from class properties:
class Config
{
public string $name;
public ?string $email = null;
public bool $debug = false;
}
$schema = Expect::from(new Config);
$schema = Expect::from(new Config, [
'email' => Expect::email()->required(),
]);
Deprecation
$schema = Expect::structure([
'oldOption' => Expect::int()->deprecated('Use newOption instead'),
'newOption' => Expect::int(),
]);
$processor->process($schema, $data);
$warnings = $processor->getWarnings();
Practical Examples
Configuration validation:
$configSchema = Expect::structure([
'database' => Expect::structure([
'driver' => Expect::anyOf('mysql', 'pgsql', 'sqlite')->required(),
'host' => Expect::string('localhost'),
'port' => Expect::int(),
'name' => Expect::string()->required(),
'user' => Expect::string()->required(),
'password' => Expect::string()->nullable(),
])->castTo('array'),
'cache' => Expect::structure([
'enabled' => Expect::bool(true),
'ttl' => Expect::int(3600)->min(0),
]),
'mail' => Expect::structure([
'from' => Expect::email()->required(),
'smtp' => Expect::structure([
'host' => Expect::string(),
'port' => Expect::int(587),
'secure' => Expect::anyOf('tls', 'ssl', null),
]),
]),
]);
API input validation:
$createUserSchema = Expect::structure([
'username' => Expect::string()
->required()
->min(3)->max(20)
->pattern('[a-z0-9_]+'),
'email' => Expect::email()->required(),
'password' => Expect::string()->required()->min(8),
'roles' => Expect::listOf(
Expect::anyOf('user', 'admin', 'moderator')
)->default(['user']),
])->castTo('array');
Online Documentation
For detailed information, use WebFetch on these URLs:
- Schema – complete Schema library guide with all Expect methods