respect/validation
Powerful PHP validation engine with 150+ tested validators. Build readable, chainable rules like numeric()->positive()->between(). Includes advanced exception handling and thorough docs. Great for complex input validation in any PHP app.
Full Changelog: https://github.com/Respect/Validation/compare/3.1.1...3.1.2
Full Changelog: https://github.com/Respect/Validation/compare/3.1.0...3.1.1
Full Changelog: https://github.com/Respect/Validation/compare/3.0.2...3.1.0
Full Changelog: https://github.com/Respect/Validation/compare/3.0.1...3.0.2
Respect\Validation 3.0 is a major release with breaking changes, improved performance, and new features for more flexible validation. This version requires PHP 8.5+ (up from 8.1+ in 2.x). Update via:
composer require respect/validation:^3.0
For detailed migration instructions, see the Migration Guide.
Validator renamed to ValidatorBuilderRules namespace to ValidatorsRule interface to ValidatorFactory to ValidatorFactoryInvalidRuleConstructorException to InvalidValidatorException.validate() now returns a ResultQuery object instead of a boolean (use isValid() for boolean checks)check() and assert() now throw a unified ValidationException (validator-specific exceptions removed; NestedValidationException removed).Type (use specific type validators like stringType())Yes/No (use trueVal()/falseVal())KeyNested (use nested key())Age/MinAge/MaxAge (use dateTimeDiff())PrimeNumber/Fibonacci/PerfectSquare/FilterVar/Uploaded (use satisfies())VideoUrl (no direct replacement).Attribute replaced by Property/PropertyOptional/PropertyExistsKey split into Key/KeyOptional/KeyExistsLength and Size signatures changed to use composition (e.g., length(v::between(5, 10)))Each stricter (rejects non-iterables like stdClass)AllOf, etc.) require at least two validatorsAfter (ex-Call) no longer handles callback errorsContains/ContainsAny/In/EndsWith/StartsWith now strict by defaultUrl validates domains/IPs, drops news scheme, adds Email for mailtosokil/php-isocodes, ramsey/uuid).Call to AfterCallback to SatisfiesMin to GreaterThanOrEqualMax to LessThanOrEqualNullable to NullOrOptional to UndefOrKeyValue to FactoryNotBlank inverted to Blank (use not(v::blank()))NotEmpty inverted/renamed to Falsy (use not(v::falsy()))NoWhitespace inverted/renamed to Spaced (use not(v::spaced()))IterableType to IterableVal (stricter IterableType now exists separately).setTemplate() and setName() removed (use templated() and named()){{name}} placeholder renamed to {{subject}}.Factory replaced by PSR-11 container via ContainerRegistry.#[Template] attributes on validator classes.Result-Based Validation: validate() returns a ResultQuery for detailed error inspection.
$result = v::numericVal()->positive()->between(1, 255)->validate($input);
$result->hasFailed(); // bool
$result->getFullMessage(); // All errors as tree
Attribute Validation: Validate object properties via PHP attributes.
class User {
#[Validators\Email] public string $email;
#[Validators\Between(18, 120)] public int $age;
}
v::attributes()->assert($user); // Validates all annotated properties
ShortCircuit Validation: Stops at first failure for dependent checks.
v::shortCircuit(
v::key('countryCode', v::countryCode()),
v::factory(fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countryCode'])))
)->assert(['countryCode' => 'US', 'subdivisionCode' => 'CA']); // Passes
Dynamic Factory Validators: Create validators based on input.
v::factory(fn($input) => v::key('confirmation', v::equals($input['password'] ?? null)))
->assert(['password' => 'secret', 'confirmation' => 'secret']); // Passes
Prefixed Shortcuts: Convenient wrappers for common patterns.
v::nullOrEmail()->assert(null); // Passes
v::allPositive()->assert([1, 2, 3]); // Passes
v::notBlank()->assert('hello'); // Passes
Result Composition: Nested results for clearer messages (e.g., all(v::intType()) → "Every item must be an integer").
Paths in Errors: Full dot-notation paths for nested failures (e.g., .mysql.host must be a string).
Helpful Stack Traces: Traces point to user code, not library internals.
Custom Exceptions: Pass exceptions to assert().
v::email()->assert($input, new DomainException('Invalid email'));
Placeholder Pipes: Customize template rendering (e.g., {{haystack|list:or}} → "active" or "pending").
Symfony Translation: Uses Symfony contracts for message translation.
New Validators: All, BetweenExclusive, ContainsCount, DateTimeDiff, Formatted, Hetu, KeyExists, KeyOptional, Named, PropertyExists, PropertyOptional, Templated.
For more details, see the Feature Guide, Validators List, or open an issue on GitHub.
This release just deprecates a few things to prepare users to the next major version. Migrating to this release will probably make migrating to version 3.0 a bit less painful, but feel free to skip this version as it has no new features.
Here are a few important changes coming into version 3.0.
validate() is now called isValid()The method validate() will be repurposed to return an object with failures, so users can iterate over them and get more detailed information about the validation that just occurred.
Consider changing your code as indicated below:
- v::stringType()->validate($input)
+ v::stringType()->isValid($input)
In most cases, a single find and replace from your IDE should fix it. You could also run a a few commands in your command line to fix that too; here's an example:
rg '\->validate\(' --files-with-matches |
xargs -n 1 sed --in-place 's,->validate(,->isValid(,g'
WARNING: the commands above will replace any method that is called validate in your codebase. Make sure that you only call the method validate from this library.
All existing methods in the class rules rules will be removed in favor of a single method that will return an object with the validation result. That will help us with providing more granularity control, more flexibility, and more rich and customisable validation messages.
Consider changing your code as indicated below:
Calling assert():
- (new Email())->assert($input)
+ Validator::create(new Email())->assert($input)
Calling check():
- (new Email())->check($input)
+ Validator::create(new Email())->check($input)
Calling validate():
- (new Email())->validate($input)
+ Validator::create(new Email())->isValid($input)
All exception messages will be removed. Instead, users will need to catch ValidationException or NestedValidationException. The current exceptions can be quite complex, and although they're heavily tested, it's not a good idea to have to much logic after a code already fails.
Consider changing your code as indicated below:
-use Respect\Validation\Exceptions\EmailException;
+use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Validator as v;
try {
v::email()->assert('invalid-email');
-} catch(EmailException $exception) {
+} catch(ValidationException $exception) {
echo $exception->getMessage() . PHP_EOL;
}
CAVEAT: The NestedValidationException will also be removed by a simplified version of ValidationException, but there's no substitute for it at the moment.
AbstractRule is now called SimpleWe no longer use Abstract as a prefix, and since the validate() method will be deprecated, and we no longer can call rules directly, the API of this class needs to change to something else.
Consider changing your code as indicated below.
-use Respect\Validation\Rules\AbstractRule;
+use Respect\Validation\Rules\Core\Simple;
-final class MyRule extends AbstractRule
+final class MyRule extends Simple
{
- public function validate($input): bool
+ public function isValid(mixed $input): bool
AbstractWrapper is now called WrapperWe no longer use Abstract as a prefix.
Consider changing your code as indicated below:
-use Respect\Validation\Rules\AbstractWrapper;
+use Respect\Validation\Rules\Core\Wrapper;
-final class MyRule extends AbstractWrapper
+final class MyRule extends Wrapper
AbstractEnvelope is now called EnvelopeWe no longer use Abstract as a prefix.
Consider changing your code as indicated below:
-use Respect\Validation\Rules\AbstractEnvelope;
+use Respect\Validation\Rules\Core\Envelope;
-final class MyRule extends AbstractEnvelope
+final class MyRule extends Envelope
AbstractComposite is now called CompositeWe no longer use Abstract as a prefix, and a Composite class needs to have at least 2 rules to be able to compare them.
Consider changing your code as indicated below:
-use Respect\Validation\Rules\AbstractComposite;
+use Respect\Validation\Rules\Core\Composite;
-final class MyRule extends AbstractComposite
+final class MyRule extends Composite
There will be a lot more deprecations coming in version 3.0, but not all of them can be described in an in-between version like this one. Version 3.0 should be coming in the upcoming month or months, but I can't make promises because life has been quite unpredictable in 2024; who knows what's coming in 2025?!
Full Changelog: https://github.com/Respect/Validation/compare/2.3.13...2.4.0
Full Changelog: https://github.com/Respect/Validation/compare/2.3.12...2.3.13
Full Changelog: https://github.com/Respect/Validation/compare/2.3.11...2.3.12
Full Changelog: https://github.com/Respect/Validation/compare/2.3.10...2.3.11
Full Changelog: https://github.com/Respect/Validation/compare/2.3.9...2.3.10
Full Changelog: https://github.com/Respect/Validation/compare/2.3.8...2.3.9
Multiple is passed an invalid value by @dmjohnsson23 in https://github.com/Respect/Validation/pull/1467Full Changelog: https://github.com/Respect/Validation/compare/2.3.7...2.3.8
Full Changelog: https://github.com/Respect/Validation/compare/2.3.6...2.3.7
Full Changelog: https://github.com/Respect/Validation/compare/2.3.5...2.3.6
Full Changelog: https://github.com/Respect/Validation/compare/2.3.4...2.3.5
Versioning Changes:
Deprecations:
Fixes:
KeySet now reports which extra keys are causing the rule to fail.Changes:
KeySet in Not.Phone now uses giggsey/libphonenumber-for-php, this package needs
to be installed if you want to use this validator.Phone now supports the parameter $countryCode to validate phones
of a specific country.Versioning Changes:
Deprecations:
Fixes:
KeySet now reports which extra keys are causing the rule to fail.Changes:
KeySet in Not.Phone now uses giggsey/libphonenumber-for-php, this package needs
to be installed if you want to use this validator.Phone now supports the parameter $countryCode to validate phones
of a specific country.The Respect team is proud to announce the release of Respect\Validation 2.24 🐼 This version is also already available on packagist.
This is a dusting-off release with most of the PRs since 2.2.3 being merged, compatibility for newer PHP versions adjusted and a new lead maintainer (@alganet, which is the original library author).
It is expected that 2.2.4 will be the last release of the 2.2.x series, with 2.3 following soon after.
Feedback and bug reports are highly appreciated. Feel free to get in touch either via Issues or Discussions.
Happy Validatin'
Meta:
Versioning Changes:
Deprecations:
Fixes:
v::decimal() for float values (thanks @scruwi)v::portugueseNif() to validate Número de Identificação Fiscal in Portugal (thanks @goncalo-andrade).v::intval() now handles negative values with trailing zeroes better (thanks @l-x)Drop support for PHP 7.2.
The Respect development team announces the immediate availability of Respect\Validation 2.0.0.
This release adds nineteen new rules, improvements, and bug fixes.
This version is been in the master branch for a long time, it’s not perfect, but it is good enough.
We would like to thanks to all the developers who spent their free time to contribute to this project. Without you, this release would be impossible. Especially:
Also, Jetbrains for providing a License that allowed me to refactor a lot faster using PHPStorm.
This version (2.0) has more than 8k backward compatibility breaks 1 with the last version (1.1). Most of them, are all the classes becoming final and public properties becoming private, but there are some other big ones. All those backward compatibility breaks help Validation to be easier to maintain, allowing us to release more and more often.
Below a more detailed list of the main backward compatibility breaks:
There are many reasons why classes should be final 2. Most classes we have are self-contained, and there are not many cases that inheritance is necessary. We want to encourage users to use them to use composition rather than inheritance, especially if we are talking about the rules, and for that same reason, we are also focusing on making their APIs clearer.
Public properties are one of the enemies of maintainability because they make the objects mutable and unpredictable. With them, we cannot ensure an object has a valid state, and we need to validate the properties before using them. Besides, changing a property name is a background compatibility break.
In this version, the whole codebase uses PHP 7.1 type-hinting. They are also using strict typing.
In the last versions, those methods were supposed to return a boolean value or throw an exception. However, in practice, those methods throw an exception when the validation fails and return TRUE when the validation passes.
In this version, those methods don't return any value: when it throws an exception it means that the validation failed; when they don't throw an exception it means that the validation passed.
After trying to fix its behavior many times, it was clear that the method itself was very confusing. Also, it became unnecessary due to how Validation evolved during the development of version 2.0.
In older versions, that method is mainly used to translate, customize templates, and retrieve the messages in an array structure.
In this version, users can configure a global translator in the Factory. As for the customization and to retrieve the messages in an array structure, users can use "NestedValidationException::getMessages()" that does a much better job.
Because of the reasons mentioned above, and for the fact that "NestedValidationException::findMessages()" is so high maintenance as a consequence of all its edge cases, it made sense to remove it from the codebase.
In the previous versions, user could overwrite Validation rules using with(), not they can’t./
In the last version, the OneOf rule validation passes if any assigned rule validation passes. In this version, the OneOf rule validation pass if only one of the assigned rule validation passes.
We also created the AnyOf rule in which the validation passes if any assigned rule validation passes.
In the last version, the Date rule validation passes if the input is a date, time, or date and time. However, it does not provide a way to be specific about the validation of date or time.
In this version, the Date rule validation passes only if the input is a date. We also created a Time rule to validate time, and a DateTime rule to validate date and time (as Date used to be).
In the last version, Min, Max, and Between allow users to define whether the validation is inclusive or exclusive with a boolean value in their constructor. Those boolean values not made the complexity or those rules higher, but also confusing sometimes.
In this version, the validation of those rules is always inclusive, and to use Between you need it is necessary to provide both minimum and maximum values. To help with non-inclusive validation we created LessThan and GreaterThan rules.
In this version, the Each rule can validate both keys and values of the input. In this version, the Each rule can only validate the values of the input.
How can I help you explore Laravel packages today?