Migrating from v2.x to v3.x
This guide will help you migrate your code from Respect\Validation 2.x to 3.0.
Version 3.0 is a major release with breaking changes. This document is organized into two main sections: Breaking Changes (what you must update) and New Features (what you can now use).
Installation
Update your composer.json to require version 3.0:
composer require respect/validation:^3.0
Respect\Validation 3.0 requires PHP 8.5 or above (2.x required PHP 8.1+).
Breaking changes
Class and namespace changes
Main class rename
The main Validator class has been renamed to ValidatorBuilder:
- use Respect\Validation\Validator as v;
+ use Respect\Validation\ValidatorBuilder as v;
Alternatively, v is now a global class alias, so you can use it directly without any import:
- use Respect\Validation\Validator as v;
v::intType()->assert($input);
Internal terminology
Throughout the codebase, "rules" have been renamed to "validators":
| 2.x | 3.0 |
|---|---|
Respect\Validation\Rules namespace |
Respect\Validation\Validators namespace |
Rule interface |
Validator interface |
AbstractRule class |
Base classes in Validators\Core |
Factory class |
ValidatorFactory class |
InvalidRuleConstructorException |
InvalidValidatorException |
Validation methods
validate() now returns an object
In 2.x, validate() returned a boolean. In 3.0, it returns a ResultQuery object:
- if (v::intType()->validate($input)) {
+ if (v::intType()->isValid($input)) {
// validation passed
}
check() and assert() behavior changes
In 2.x, both check() and assert() threw validator-specific exception classes (e.g., IntTypeException), which were children of ValidationException. The difference was that check() threw these exceptions directly and stopped at the first failure, while assert() threw a NestedValidationException (also a child of ValidationException) that collected all errors and provided methods like getFullMessage() and getMessages() not available on the base ValidationException.
In 3.0, validator-specific exception classes and NestedValidationException no longer exist. Both check() and assert() throw a unified ValidationException that includes getMessage(), getFullMessage(), and getMessages(). The behavioral distinction is preserved: check() still fails fast (stopping at the first failure, using ShortCircuit internally), while assert() collects all errors.
-use Respect\Validation\Exceptions\IntTypeException;
+use Respect\Validation\Exceptions\ValidationException;
try {
v::intType()->check($input);
-} catch (IntTypeException $exception) {
+} catch (ValidationException $exception) {
echo $exception->getMessage();
}
-use Respect\Validation\Exceptions\NestedValidationException;
+use Respect\Validation\Exceptions\ValidationException;
try {
v::intType()->positive()->assert($input);
-} catch (NestedValidationException $exception) {
+} catch (ValidationException $exception) {
$exception->getMessage(); // First error message
$exception->getFullMessage(); // Full error tree
$exception->getMessages(); // All errors as array
}
Validator changes
Removed validators
Type
The type() validator has been replaced in favor of specific type validators:
- v::type('string')->assert($input);
+ v::stringType()->assert($input);
- v::type('int')->assert($input);
+ v::intType()->assert($input);
- v::type('array')->assert($input);
+ v::arrayType()->assert($input);
Yes and No
- v::yes()->assert('yes');
+ v::trueVal()->assert('yes');
- v::no()->assert('no');
+ v::falseVal()->assert('no');
KeyNested
- v::keyNested('user.profile.name', v::stringType())->assert($data);
+ v::key('user', v::key('profile', v::key('name', v::stringType())))->assert($data);
Age, MinAge, and MaxAge
These validators have been replaced by DateTimeDiff, which provides more flexibility by allowing you to specify the time unit and comparison validator:
- v::minAge(18)->assert($birthDate);
+ v::dateTimeDiff('years', v::greaterThanOrEqual(18))->assert($birthDate);
- v::maxAge(65)->assert($birthDate);
+ v::dateTimeDiff('years', v::lessThanOrEqual(65))->assert($birthDate);
- v::age(18, 65)->assert($birthDate);
+ v::dateTimeDiff('years', v::between(18, 65))->assert($birthDate);
PrimeNumber, Fibonacci, PerfectSquare
Combine Satisfies with a mathematical library of your choice:
- v::primeNumber()->assert(7);
+ v::satisfies(static fn ($input) => \MathPHP\NumberTheory\Integer::isPrime($input))->assert(7);
See: https://github.com/markrogoyski/math-php
FilterVar
Use Satisfies instead:
- v::filterVar(FILTER_VALIDATE_INT)->assert(123);
+ v::satisfies(static fn($input) => filter_var($input, FILTER_VALIDATE_INT) !== false)->assert(123);
Uploaded
Use Satisfies instead:
- v::uploaded()->assert($fileName);
+ v::satisfies('is_uploaded_file')->assert($fileName);
VideoUrl
We offer no recommendation for replacing this validator.
Behavior changes
Attribute replaced by Property variants
The Attribute validator has been replaced by three separate validators with different signatures.
| Validator | Description |
|---|---|
Property |
Property must exist and pass validation |
PropertyOptional |
Validates only if property exists |
PropertyExists |
Only checks if property exists |
// Property must exist and be valid
- v::attribute('name', v::stringType())->assert($user);
+ v::property('name', v::stringType())->assert($user);
// Property is optional (mandatory = false)
- v::attribute('age', v::intType(), false)->assert($user);
+ v::propertyOptional('age', v::intType())->assert($user);
// Only check existence (no validator, mandatory = true)
- v::attribute('id')->assert($user);
+ v::propertyExists('id')->assert($user);
Key split into three validators
The Key validator has been split into three separate validators with different signatures.
| Validator | Description |
|---|---|
Key |
Key must exist and pass validation |
KeyOptional |
Validates only if key exists |
KeyExists |
Only checks if key exists |
// Key must exist and be valid
- v::key('email', v::email())->assert($data);
+ v::key('email', v::email())->assert($data);
// Key is optional (mandatory = false)
- v::key('phone', v::phone(), false)->assert($data);
+ v::keyOptional('phone', v::phone())->assert($data);
// Only check existence (no validator, mandatory = true)
- v::key('id')->assert($data);
+ v::keyExists('id')->assert($data);
Length signature changed
The length() validator no longer accepts scalar min/max arguments. Use the new composition syntax:
- v::length(5, 10)->assert($input);
+ v::length(v::between(5, 10))->assert($input);
- v::length(5, null)->assert($input);
+ v::length(v::greaterThanOrEqual(5))->assert($input);
- v::length(null, 10)->assert($input);
+ v::length(v::lessThanOrEqual(10))->assert($input);
Or use the prefixed shortcuts:
v::lengthBetween(5, 10)->assert($input);
v::lengthGreaterThanOrEqual(5)->assert($input);
v::lengthLessThanOrEqual(10)->assert($input);
Size signature changed
The size() validator no longer accepts string sizes like '5MB'. Use the new composition syntax:
- v::size('5MB', '10MB')->assert($file);
+ v::size('MB', v::between(5, 10))->assert($file);
- v::size('5MB', null)->assert($file);
+ v::size('MB', v::greaterThanOrEqual(5))->assert($file);
- v::size(null, '10MB')->assert($file);
+ v::size('MB', v::lessThanOrEqual(10))->assert($file);
Each validator stricter
The Each validator now rejects stdClass and other non-iterable values:
// These now fail in 3.0
v::each(v::alwaysValid())->isValid(new stdClass()); // false
Composite validators require two or more validators
AllOf, AnyOf, NoneOf, and OneOf now require at least two validators:
- v::allOf(v::intType())->assert($input);
+ v::intType()->assert($input);
After does not handle errors anymore
After (previously Call) now does not handle PHP errors inside the callback you provided.
v::after('strtolower', v::equals('foo'))->assert(123); // Error bubbles out
You can use anonymous functions to handle errors or perform type conversions instead:
v::after(static fn ($i) => strtolower((string) $i), v::equals('123'));
Contains, ContainsAny, In, EndsWith and StartsWith strict by default.
The parameter $identical, which controlled case-insensitivy and strict typing was
removed. Now these validators will always compare case-sensitive and use
strict typing.
- v::contains('needle', identical: true);
- v::containsAny(['needle1', 'needle2'], identical: true);
- v::in(['hay', 'stack'], compareIdentical: true);
- v::startsWith('needle', identical: true);
- v::endsWith('needle', identical: true);
+ v::contains('needle'); // always strict case and type
+ v::containsAny(['needle1', 'needle2']); // always strict case and type
+ v::in(['hay', 'stack']); // always strict case and type
+ v::startsWith('needle'); // always strict case and type
+ v::endsWith('needle'); // always strict case and type
For more information, refer to case-sensitiveness.md
Url now validates domains, IP addresses and domains when appropriate.
newsscheme is now unsupported. Consult the validator documentation for the list of supported schemes.mailtoURLs now are also validated with theEmailvalidator.- Supported schemes now validate using
IpandDomainwhen appropriate.
New package dependencies
Some validators now require additional packages:
| Validators | Required packages |
|---|---|
CountryCode, LanguageCode, SubdivisionCode, CurrencyCode |
sokil/php-isocodes and sokil/php-isocodes-db-only |
Uuid |
ramsey/uuid |
Install with:
composer require sokil/php-isocodes sokil/php-isocodes-db-only
composer require ramsey/uuid
Renamed validators
| 2.x | 3.0 | Notes |
|---|---|---|
Call |
After |
Clearer intent |
Callback |
Satisfies |
Clearer intent |
Min |
GreaterThanOrEqual |
Clearer comparison semantics |
Max |
LessThanOrEqual |
Clearer comparison semantics |
Nullable |
NullOr |
Consistent naming pattern |
Optional |
UndefOr |
Validates if value is undefined or passes |
KeyValue |
Factory |
Deferred validator creation |
- v::call('strtolower', v::equals('foo'))->assert($input);
+ v::after('strtolower', v::equals('foo'))->assert($input);
- v::callback('is_int')->assert($input);
+ v::satisfies('is_int')->assert($input);
- v::min(18)->assert($age);
+ v::greaterThanOrEqual(18)->assert($age);
- v::max(100)->assert($age);
+ v::lessThanOrEqual(100)->assert($age);
- v::nullable(v::email())->assert($email);
+ v::nullOr(v::email())->assert($email);
- v::optional(v::email())->assert($email);
+ v::undefOr(v::email())->assert($email);
In 3.0, Min and Max validators exist but have different semantics. They extract the minimum/maximum value from a collection and validate it (see Result composition).
| Validator | 2.x | 3.x |
|---|---|---|
Min |
Single value >= | Pick minimum value from iterable and validate |
Max |
Single value <= | Pick minimum value from iterable and validate |
NotBlank logic inverted
In 2.x, NotBlank validated that a value was not blank. In 3.0, Blank validates that a value is blank, so you need to negate it:
- v::notBlank()->assert($input);
+ v::not(v::blank())->assert($input);
Or use the prefixed shortcut (see New Features):
v::notBlank()->assert($input);
NotEmpty renamed to Falsy
The NotEmpty validator was renamed to Falsy with inverted logic:
- v::notEmpty()->assert($input);
+ v::not(v::falsy())->assert($input);
Or use the prefixed shortcut:
v::notFalsy()->assert($input);
NoWhitespace renamed to Spaced
The NoWhitespace validator was renamed to Spaced with inverted logic. Spaced validates that a string contains whitespace:
- v::noWhitespace()->assert($input);
+ v::not(v::spaced())->assert($input);
Or use the prefixed shortcut:
v::notSpaced()->assert($input);
IterableType renamed to IterableVal
- v::iterableType()->assert($input);
+ v::iterableVal()->assert($input);
Note: IterableType still exists in 3.0 but now strictly uses PHP's is_iterable() function (rejecting stdClass).
Custom message methods removed
setTemplate() removed
- v::intType()->setTemplate('Please provide an integer')->check($input);
+ v::templated('Please provide an integer', v::intType())->assert($input);
setName() removed
- v::intType()->setName('User ID')->check($input);
+ v::named('User ID', v::intType())->assert($input);
{{name}} placeholder renamed
The main placeholder in message templates has been renamed from {{name}} to {{subject}}:
- {{name}} must be valid
+ {{subject}} must be valid
The value of {{subject}} is determined by context:
| Context | Value | Example |
|---|---|---|
| Key/Property/Each validators | The path | `.email` must be valid |
Named validator |
The custom name | Email must be valid |
| Both path and name defined | Path with name suffix | `.email` (<- User Email) must be valid |
| No path or name | The input value | "invalid#email" must be valid |
Factory and container changes
The Factory class has been replaced by a dependency injection container approach using ContainerRegistry:
- use Respect\Validation\Factory;
+ use Respect\Validation\ContainerRegistry;
+ use Symfony\Contracts\Translation\TranslatorInterface;
- Factory::setDefaultInstance(
- (new Factory())
- ->withRuleNamespace('My\\Validation\\Rules')
- ->withTranslator($translator)
- );
+ $container = ContainerRegistry::createContainer([
+ // Add custom validator namespaces
+ 'respect.validation.rule_factory.namespaces' => [
+ 'My\\Validation\\Validators',
+ 'Respect\\Validation\\Validators', // Keep the default namespace
+ ],
+ // Add a translator
+ TranslatorInterface::class => $translator,
+ ]);
+ ContainerRegistry::setContainer($container);
The ContainerRegistry::createContainer() returns a PHP-DI container. You can also use any PSR-11 compatible container with ContainerRegistry::setContainer().
Custom validators
In 2.x, custom validators required a separate exception class to define error message templates. In 3.0, templates are defined using PHP attributes directly on the validator class.
Before (2.x): Two files required - validator and exception:
// CustomException.php
use Respect\Validation\Exceptions\ValidationException;
final class CustomException extends ValidationException
{
protected $defaultTemplates = [
self::MODE_DEFAULT => [
self::STANDARD => '{{name}} must be custom',
],
self::MODE_NEGATIVE => [
self::STANDARD => '{{name}} must not be custom',
],
];
}
// Custom.php
use Respect\Validation\Rules\AbstractRule;
final class Custom extends AbstractRule
{
public function validate($input): bool
{
return $this->checkSomething($input);
}
// Implementation of checkSomething()...
}
After (3.0): Single file with #[Template] attribute:
use Respect\Validation\Message\Template;
use Respect\Validation\Result;
use Respect\Validation\Validator;
#[Template(
'{{subject}} must be custom',
'{{subject}} must not be custom',
)]
final class Custom implements Validator
{
public function evaluate(mixed $input): Result
{
return Result::of($this->checkSomething($input), $input, $this);
}
// Implementation of checkSomething()...
}
Base classes available in Respect\Validation\Validators\Core:
Simple- For validators with simple boolean logicComposite- For validators that combine multiple validatorsEnvelope- For validators that modify how another validator works
New features
New validators
Version 3.0 introduces several new validators:
| Validator | Description |
|---|---|
All |
Validates that every item in an iterable passes validation |
Attributes |
Validates object properties using PHP attributes |
BetweenExclusive |
Validates that a value is between two bounds (exclusive) |
ContainsCount |
Validates the count of occurrences in a value |
DateTimeDiff |
Validates date/time differences (replaces Age validators) |
Formatted |
Formats input values in error messages |
ShortCircuit |
Stops at first failure instead of collecting all errors |
Hetu |
Validates Finnish personal identity codes (henkilötunnus) |
KeyExists |
Checks if an array key exists |
KeyOptional |
Validates an array key only if it exists |
Factory |
Creates validators dynamically based on input |
Named |
Customizes the subject name in error messages |
PropertyExists |
Checks if an object property exists |
PropertyOptional |
Validates an object property only if it exists |
Templated |
Attaches custom error message templates |
All
Validates that every item in an iterable passes the given validator:
v::all(v::intType())->assert([1, 2, 3]); // passes
v::all(v::positive())->assert([1, -2, 3]); // fails
Attributes
Validates object properties using PHP attributes defined on the class:
use Respect\Validation\Validators as Validator;
final readonly class User
{
public function __construct(
#[Validator\Email]
public string $email,
#[Validator\Between(18, 120)]
public int $age,
#[Validator\Length(new Validator\Between(1, 100))]
public string $name,
) {
}
}
// Validate all properties at once
v::attributes()->assert($user);
BetweenExclusive
Validates that a value is between two bounds, excluding the bounds themselves:
v::betweenExclusive(1, 10)->assert(5); // passes
v::betweenExclusive(1, 10)->assert(1); // fails (1 is not > 1)
v::betweenExclusive(1, 10)->assert(10); // fails (10 is not < 10)
ContainsCount
Validates the count of occurrences of a value:
v::containsCount('a', v::equals(3))->assert('banana'); // passes (3 'a's)
v::containsCount('x', v::greaterThan(0))->assert('example'); // passes
DateTimeDiff
Validates date/time differences. Replaces the removed Age, MinAge, and MaxAge validators:
v::dateTimeDiff('years', v::greaterThanOrEqual(18))->assert('2000-01-01'); // passes if 18+ years ago
v::dateTimeDiff('days', v::lessThan(30))->assert('2024-01-15'); // passes if less than 30 days ago
Formatted
Decorates a validator to format input values in error messages while still validating the original input:
use Respect\StringFormatter\FormatterBuilder as f;
v::formatted(f::mask('1-4'), v::email())->assert('not an email');
// → "****an email" must be an email address
v::formatted(f::pattern('#### #### #### ####'), v::creditCard())->assert('1234123412341234');
// → "1234 1234 1234 1234" must be a credit card number
ShortCircuit
Validates input against a series of validators, stopping at the first failure. Useful for dependent validations:
$validator = v::shortCircuit(
v::key('countryCode', v::countryCode()),
v::factory(
fn($input) => v::key(
'subdivisionCode',
v::subdivisionCode($input['countryCode'])
)
),
);
$validator->assert([]); // → `.countryCode` must be present
$validator->assert(['countryCode' => 'US']); // → `.subdivisionCode` must be present
$validator->assert(['countryCode' => 'US', 'subdivisionCode' => 'CA']); // passes
Hetu
Validates Finnish personal identity codes (henkilötunnus):
v::hetu()->assert('010101-123N'); // passes
KeyExists
Checks if an array key exists (without validating its value):
v::keyExists('email')->assert(['email' => 'user@example.com']); // passes
v::keyExists('email')->assert(['name' => 'John']); // fails
KeyOptional
Validates an array key only if it exists:
v::keyOptional('phone', v::phone())->assert(['name' => 'John']); // passes (key absent)
v::keyOptional('phone', v::phone())->assert(['phone' => '+1234567890']); // passes
v::keyOptional('phone', v::phone())->assert(['phone' => 'invalid']); // fails
Factory
Creates validators dynamically based on the input, useful for cross-field validation:
// Validate that 'confirmation' matches 'password'
v::factory(
fn($input) => v::key('confirmation', v::equals($input['password'] ?? null))
)->assert(['password' => 'secret', 'confirmation' => 'secret']); // passes
Named
Customizes the subject name in error messages:
v::named('User ID', v::intType())->assert('abc');
// → User ID must be an integer
PropertyExists
Checks if an object property exists (without validating its value):
v::propertyExists('name')->assert($user); // passes if $user->name exists
PropertyOptional
Validates an object property only if it exists:
v::propertyOptional('nickname', v::stringType())->assert($user); // passes if absent
v::propertyOptional('nickname', v::stringType())->assert($user); // validates if present
Templated
Attaches custom error message templates to validators:
v::templated('Please provide a valid number', v::intType())->assert('abc');
// → Please provide a valid number
Result-based validation
The validate() method now returns a ResultQuery object that provides detailed error inspection:
$result = v::numericVal()->positive()->between(1, 255)->validate($input);
$result->hasFailed(); // Check if the validation has failed (boolean)
$result->getMessage(); // Get the first error message
$result->getFullMessage(); // Get all error messages as a tree
$result->getMessages(); // Get all error messages as an array
Finding by path
Use findByPath() to locate validation results using dot notation for nested structures:
$result = v::init()
->key('user', v::key('email', v::email()))
->key('items', v::each(v::positive()))
->validate([
'user' => ['email' => 'invalid'],
'items' => [10, -5, 20],
]);
echo $result->findByPath('user.email');
// → `.user.email` must be a valid email address
echo $result->findByPath('items.1');
// → `.items.1` must be a positive number
Finding by name
Use findByName() to locate validation results by the custom name set with the Named validator:
$result = v::named('User Email', v::email())->validate('bad');
echo $result->findByName('User Email');
// → User Email must be a valid email address
Finding by ID
Use findById() to locate validation results by the validator's ID (e.g., stringType, email):
$result = v::stringType()->email()->validate(123);
echo $result->findById('stringType');
// → 123 must be a string
All finder methods return either a ResultQuery instance or null if not found.
Prefixed shortcuts
Version 3.0 introduces convenient prefixed shortcuts for common patterns:
// Null-or validators
v::nullOrEmail()->assert(null); // passes
v::nullOrEmail()->assert('user@example.com'); // passes
// Undefined-or validators
v::undefOrPositive()->assert(null); // passes
v::undefOrPositive()->assert(5); // passes
// All (array item) validators
v::allPositive()->assert([1, 2, 3]); // passes
v::allEmail()->assert(['a@b.com', 'c@d.com']); // passes
// Key validators
v::keyEmail('email')->assert(['email' => 'user@example.com']); // passes
// Property validators
v::propertyPositive('age')->assert($user); // passes if $user->age is positive
// Length validators
v::lengthBetween(5, 10)->assert('hello'); // passes
// Min/Max validators
v::minGreaterThan(0)->assert([1, 2, 3]); // passes
v::maxLessThan(10)->assert([1, 2, 3]); // passes
// Negation prefix
v::notBlank()->assert('hello'); // passes
Result composition
Validators compose results for clearer error messages:
v::all(v::intType())->assert(['1', '2', '3']);
// → Every item in ["1", "2", "3"] must be an integer
v::length(v::greaterThan(3))->assert('abc');
// → The length of "abc" must be greater than 3
v::key('age', v::greaterThanOrEqual(18))->assert(['age' => 16]);
// → `.age` must be greater than or equal to 18
Paths in error messages
Error messages now include full paths for nested structures:
v::init()
->key('mysql', v::init()->key('host', v::stringType()))
->key('postgresql', v::init()->key('host', v::stringType()))
->assert($input);
// → `.mysql.host` must be a string
Helpful stack traces
When validation fails, stack traces now point to your code instead of library internals.
2.x:
Stack trace:
#0 /opt/vendor/respect/validation/library/Factory.php(233): ReflectionClass->newInstance(1.0, 'intVal', Array, Object(Respect\Validation\Message\Formatter))
#1 /opt/vendor/respect/validation/library/Factory.php(164): Respect\Validation\Factory->createValidationException('Respect\\Validat...', 'intVal', 1.0, Array, Object(Respect\Validation\Message\Formatter))
#2 /opt/vendor/respect/validation/library/Rules/AbstractRule.php(70): Respect\Validation\Factory->exception(Object(Respect\Validation\Rules\IntVal), 1.0, Array)
#3 /opt/vendor/respect/validation/library/Rules/AbstractRule.php(45): Respect\Validation\Rules\AbstractRule->reportError(1.0)
#4 /opt/vendor/respect/validation/library/Rules/AbstractRule.php(53): Respect\Validation\Rules\AbstractRule->assert(1.0)
#5 /opt/vendor/respect/validation/library/Rules/AllOf.php(50): Respect\Validation\Rules\AbstractRule->check(1.0)
#6 /opt/vendor/respect/validation/library/Validator.php(68): Respect\Validation\Rules\AllOf->check(1.0)
#7 /opt/example.php(11): Respect\Validation\Validator->check(1.0)
#8 {main}
3.0:
Stack trace:
#0 /opt/example.php(11): Respect\Validation\Validator->assert(1.0)
#1 {main}
Custom exceptions in assert()
Pass your own exception directly to assert():
v::email()->assert($input, new DomainException('Invalid email'));
Or use a callable to access the original exception message:
v::email()->assert(
$input,
fn(ValidationException $e) => new DomainException($e->getMessage()),
);
Translation
The project now uses Symfony translation contracts instead of a custom callback.
See messages/translation.md for more info.
Placeholder pipes
Customize how values are rendered in templates using pipes:
// `|raw` - removes quotes
v::templated(
'{{subject|raw}} is not a UUID v{{version}}',
v::uuid(1),
)->assert('eb3115e5-bd16-4939-ab12-2b95745a30f3');
// → eb3115e5-bd16-4939-ab12-2b95745a30f3 is not a UUID v1
// `|quote` - uses backticks
v::templated(
'Value must match {{pattern|quote}}',
v::regex('/^\d+$/'),
)->assert('abc');
// → Value must match `/^\d+$/`
// `|trans` - translates the value (when using a translator)
v::templated(
'Le champ {{field|trans}} est invalide',
v::email(),
['field' => 'email_address'],
)->assert('invalid');
// → Le champ "adresse e-mail" est invalide
// `|list:or` and `|list:and` - formats arrays as readable lists
v::templated(
'Status must be {{haystack|list:or}}',
v::in(['active', 'pending']),
)->assert('deleted');
// → Status must be "active" or "pending"
Quick reference
// Main class
- use Respect\Validation\Validator as v;
+ use Respect\Validation\ValidatorBuilder as v;
// Boolean validation (unchanged)
v::intType()->isValid($input);
// Result-based validation
- v::intType()->validate($input); // bool
+ v::intType()->isValid($input); // bool
// Exception-based validation (fail-fast)
- v::intType()->check($input); // IntTypeException (child of ValidationException)
+ v::intType()->check($input); // ValidationException
// Exception-based validation (collect all errors)
- v::intType()->assert($input); // AllOfExceptopn (child of NestedValidationException)
+ v::intType()->assert($input); // ValidationException
// Renamed validators
- v::min(18);
+ v::greaterThanOrEqual(18);
- v::max(100);
+ v::lessThanOrEqual(100);
- v::nullable(v::email());
+ v::nullOr(v::email());
// Attribute → Property
- v::attribute('name', v::stringType());
+ v::property('name', v::stringType());
- v::attribute('age', v::intType(), false);
+ v::propertyOptional('age', v::intType());
- v::attribute('id');
+ v::propertyExists('id');
// Key changes
- v::key('phone', v::phone(), false);
+ v::keyOptional('phone', v::phone());
- v::key('id');
+ v::keyExists('id');
// Removed validators
- v::keyNested('a.b.c', $validator);
+ v::key('a', v::key('b', v::key('c', $validator)));
- v::yes();
+ v::trueVal();
- v::no();
+ v::falseVal();
- v::minAge(18);
+ v::dateTimeDiff('years', v::greaterThanOrEqual(18));
- v::maxAge(65);
+ v::dateTimeDiff('years', v::lessThanOrEqual(65));
Getting help
- Check the Feature Guide for detailed usage examples
- Browse the List of Validators for validator-specific documentation
- Review the article What's New in Respect\Validation 3.0
- Open an issue on GitHub if you find bugs or have questions