Configuring Validation Groups in Forms
If the object handled in your form uses validation groups, you need to specify which validation group(s) the form should apply.
To define them when creating forms in classes,
use the configureOptions()
method:
1 2 3 4 5 6 7 8 9
use Symfony\Component\OptionsResolver\OptionsResolver;
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
// ...
'validation_groups' => ['registration'],
]);
}
When creating forms in controllers, pass it as a form option:
1 2 3
$form = $this->createFormBuilder($user, [
'validation_groups' => ['registration'],
])->add(/* ... */);
In both cases, only the registration
group will be used to validate the
object. To apply the registration
group and all constraints not in any
other group, add the special Default
group:
1 2 3 4
[
// ...
'validation_groups' => ['Default', 'registration'],
]
Note
You can use any name for your validation groups. Symfony recommends using
"lower snake case" (e.g. foo_bar
), while automatically generated
groups use "UpperCamelCase" (e.g. Default
, SomeClassName
).
Choosing Validation Groups Based on the Clicked Button
When your form has multiple submit buttons, you can change the validation group based on the clicked button. For example, in a multi-step form like the following, you might want to skip validation when returning to a previous step:
1 2 3 4 5
$form = $this->createFormBuilder($task)
// ...
->add('nextStep', SubmitType::class)
->add('previousStep', SubmitType::class)
->getForm();
To do so, configure the validation groups of the previousStep
button to
false
, which is a special value that skips validation:
1 2 3 4 5 6
$form = $this->createFormBuilder($task)
// ...
->add('previousStep', SubmitType::class, [
'validation_groups' => false,
])
->getForm();
Now the form will skip your validation constraints when that button is clicked. It will still validate basic integrity constraints, such as checking whether an uploaded file was too large or whether you tried to submit text in a number field.
Choosing Validation Groups Based on Submitted Data
To determine validation groups dynamically based on submitted data, use a callback. This is called after the form is submitted, but before validation is invoked. The callback receives the form object as its first argument:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
use App\Entity\Client;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'validation_groups' => function (FormInterface $form): array {
$data = $form->getData();
if (Client::TYPE_PERSON === $data->getType()) {
return ['Default', 'person'];
}
return ['Default', 'company'];
},
]);
}
Note
Adding Default
to the list of validation groups is common but not mandatory.
See the main article about validation groups to
learn more about validation groups and the default constraints.
You can also pass a static class method callback:
1
'validation_groups' => [Client::class, 'determineValidationGroups']
Choosing Validation Groups via a Service
If validation group logic requires services or can't fit in a closure, use a dedicated validation group resolver service. The class of this service must be invokable and receives the form object as its first argument:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
// src/Validation/ValidationGroupResolver.php
namespace App\Validation;
use Symfony\Component\Form\FormInterface;
class ValidationGroupResolver
{
public function __construct(
private object $service1,
private object $service2,
) {
}
public function __invoke(FormInterface $form): array
{
$groups = [];
// ... determine which groups to return
return $groups;
}
}
Then use the service in your form type:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
namespace App\Form;
use App\Validation\ValidationGroupResolver;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MyClassType extends AbstractType
{
public function __construct(
private ValidationGroupResolver $groupResolver,
) {
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'validation_groups' => $this->groupResolver,
]);
}
}
Learn More
For more information about how validation groups work, see How to Apply only a Subset of all Your Validation Constraints (Validation Groups).