Constraints¶
Each Constraint have the following methods:
->__invoke()->and()->guard()->or()->xor()->map()->asPredicate()->failWith()
->__invoke()¶
This method is the one to apply the validation on an input and will return a Validation monad that will contain either the validated data or the error messages.
Let's take a simple example to check if the input of a method is a string:
use Innmind\Validation\Is;
function(mixed $input): string {
$validate = Is::string();
return $validate($input)->match(
static fn(string $value) => $value,
static fn() => throw new \RuntimeException('Input is not a string');
);
}
Info
Note that we use the style $validate($input) and not $validate->__invoke($input). This style allows to treat the constraints as if it were native functions.
->and()¶
This method allows to apply extra validation on an input.
Let's take the example of making sure a string is shorter than 255 characters:
use Innmind\Validation\{
Is,
Constraint,
Failure,
};
use Innmind\Immutable\Validation;
function(mixed $input): string {
$validate = Is::string()->and(Constraint::of(
static fn(string $value) => match (true) {
\strlen($value) < 255 => Validation::success($value),
default => Validation::fail(Failure::of('String is too long')),
},
));
return $validate($input)->match(
static fn(string $value) => $value,
static fn() => throw new \RuntimeException('Input is not valid');
);
}
->guard()¶
This is like ->and() except that the failures of the constraint passed as argument won't be recovered by a call to ->xor().
->or()¶
This method allows to have an alternate validation in case the first one fails. This is useful for unions types.
Let's take the example where the input needs to be a string or an int:
use Innmind\Validation\Is;
function(mixed $input): string|int {
$validate = Is::string()->or(Is::int());
return return $validate($input)->match(
static fn(string|int $value) => $value,
static fn() => throw new \RuntimeException('Input is not valid'),
);
}
->xor()¶
use Innmind\Validation\Is;
$validate = Is::string()
->guard(Is::value('foobar'))
->xor(Is::int());
$validate($value)->match(
static fn(string|int $value) => $value,
static fn() => throw new \RuntimeException('Input is not valid'),
);
Unlike ->or(), if $value is any string other than foobar this will raise an exception. This is because the failure due to Is::value('foobar') is guarded.
This is the only combination preventing a failure from being recovered. Replacing ->guard() by ->and() or ->xor() by ->or() will work the same way as ->and()->or().
->map()¶
This method allows to transform the validated value to anything you want.
Let's take the example where a need a string but want to output a Str for ease of use afterwards:
use Innmind\Validation\Is;
use Innmind\Immutable\Str;
function(mixed $input): Str {
$validate = Is::string()->map(
static fn(string $value) => Str::of($value),
);
return return $validate($input)->match(
static fn(Str $value) => $value,
static fn() => throw new \RuntimeException('Input is not valid');
);
}
->asPredicate()¶
A Predicate acts as a function that returns a bool.
It's intended to be used with Sequence::keep() or Set::keep().
Here's an example to keep all strings inside a Sequence:
use Innmind\Validation\Is;
use Innmind\Immutable\Sequence;
Sequence::of(1, 'a', null, 'b', new \stdClass, 'c')
->keep(Is::string()->asPredicate())
->toList(); // returns ['a', 'b', 'c']
Note
There's no need to apply transformations on your constraints when used as predicates as the outputed value is not used.
->failWith()¶
This method allows to change the failure message.
use Innmind\Validation\Is;
$password = Is::string()->failWith('The password is required');
$password($someInput);
Handling failures¶
In the examples above we've thrown exceptions in case of errors but you have access to all the failures messages and where they happened.
use Innmind\Validation\{
Is,
Failure,
};
use Innmind\Immutable\Sequence;
$validate = Is::shape('id', Is::int())
->with('username', Is::string());
$validate($input)->match(
static fn(array $valid) => $valid,
static fn(Sequence $failures) => \var_dump(
$failures
->map(static fn(Failure $failure) => [
$failure->path()->toString(),
$failure->message(),
])
->toList(),
),
);
In case $input is invalid it will print: