Sequentially
This constraint allows you to apply a set of rules that should be validated step-by-step, allowing you to interrupt the validation once the first violation is raised.
As an alternative in situations Sequentially cannot solve, you may consider
using GroupSequence which allows more control.
| Applies to | property or method |
| Class | Sequentially |
| Validator | SequentiallyValidator |
Basic Usage
Suppose that you have a Place object with an $address property which
must match the following requirements:
- it's a non-blank string
- of at least 10 chars long
- with a specific format
- and geolocalizable using an external service
In such situations, you may encounter three issues:
- the
LengthorRegexconstraints may fail hard with a UnexpectedValueException exception if the actual value is not a string, as enforced byType. - you may end with multiple error messages for the same property.
- you may perform a useless and heavy external call to geolocalize the address, while the format isn't valid.
You can validate each of these constraints sequentially to solve these issues:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// src/Localization/Place.php
namespace App\Localization;
use App\Validator\Constraints as AcmeAssert;
use Symfony\Component\Validator\Constraints as Assert;
class Place
{
private const string ADDRESS_REGEX = '...';
#[Assert\Sequentially([
new Assert\NotNull,
new Assert\Type('string'),
new Assert\Length(min: 10),
new Assert\Regex(Place::ADDRESS_REGEX),
new AcmeAssert\Geolocalizable,
])]
public string $address;
// ...
}
Conditionally Cascading Validation
8.2
Support for the Valid constraint inside Sequentially was introduced
in Symfony 8.2.
When a property can hold values of different types (e.g. user input that can be
a string or an object), you may want to validate the nested object only after
checking that it's an instance of the expected class. Applying the
Type and
Valid constraints separately doesn't
work, because both always run. Instead, add Valid after Type inside
Sequentially:
1 2 3 4 5 6 7 8 9 10 11 12 13
// src/Model/ImportRequest.php
namespace App\Model;
use Symfony\Component\Validator\Constraints as Assert;
class ImportRequest
{
#[Assert\Sequentially([
new Assert\Type(ResourceInput::class),
new Assert\Valid(),
])]
public mixed $resource = null;
}
If $resource is not a ResourceInput object, Type adds a violation
and the sequence stops. Otherwise, Valid validates the constraints of that
object. Always add Valid after the constraints that check the value type;
if Valid runs first on a scalar value, an exception is thrown.
The nested Valid constraint can't define the groups option. Define it
in Sequentially instead. These groups are also the ones used to validate
the nested object. For example, with groups: ['import'], only the
import constraints of the nested object run; add Default to that list
to also run its Default constraints.
Valid can't be used directly inside other composite constraints (such as
All or AtLeastOneOf). Instead, wrap it in a Sequentially constraint
and add that to the other composite constraint.
Options
constraints
type: array
This required option is the array of validation constraints that you want to apply sequentially.
groups
type: array | string default: null
It defines the validation group or groups of this constraint. Read more about validation groups.
payload
type: mixed default: null
This option can be used to attach arbitrary domain-specific data to a constraint. The configured payload is not used by the Validator component, but its processing is completely up to you.
For example, you may want to use several error levels to present failed constraints differently in the front-end depending on the severity of the error.