Skip to content

[Form][Validator] Merge all articles about using validation groups in forms #21159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: 6.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions _build/redirection_map
Original file line number Diff line number Diff line change
Expand Up @@ -570,3 +570,6 @@
/components/serializer /serializer
/serializer/custom_encoder /serializer/encoders#serializer-custom-encoder
/components/string /string
/form/button_based_validation /form/validation_groups
/form/data_based_validation /form/validation_groups
/form/validation_group_service_resolver /form/validation_groups
36 changes: 0 additions & 36 deletions form/button_based_validation.rst

This file was deleted.

72 changes: 0 additions & 72 deletions form/data_based_validation.rst

This file was deleted.

58 changes: 0 additions & 58 deletions form/validation_group_service_resolver.rst

This file was deleted.

164 changes: 144 additions & 20 deletions form/validation_groups.rst
Original file line number Diff line number Diff line change
@@ -1,39 +1,163 @@
How to Define the Validation Groups to Use
==========================================
Configuring Validation Groups in Forms
======================================

Validation Groups
-----------------
If the object handled in your form uses :doc:`validation groups </validation/groups>`,
you need to specify which validation group(s) the form should apply.

If your object takes advantage of :doc:`validation groups </validation/groups>`,
you'll need to specify which validation group(s) your form should use. Pass
this as an option when :ref:`creating forms in controllers <creating-forms-in-controllers>`::
To define them when :ref:`creating forms in classes <creating-forms-in-classes>`,
use the ``configureOptions()`` method::

use Symfony\Component\OptionsResolver\OptionsResolver;

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
// ...
'validation_groups' => ['registration'],
]);
}

When :ref:`creating forms in controllers <creating-forms-in-controllers>`, pass
it as a form option::

$form = $this->createFormBuilder($user, [
'validation_groups' => ['registration'],
])->add(/* ... */);

When :ref:`creating forms in classes <creating-forms-in-classes>`, add the
following to the ``configureOptions()`` method::
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::

[
// ...
'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 :doc:`multiple submit buttons </form/multiple_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::

$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::

$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::

use App\Entity\Client;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
// ...
'validation_groups' => ['registration'],
'validation_groups' => function (FormInterface $form): array {
$data = $form->getData();

if (Client::TYPE_PERSON === $data->getType()) {
return ['Default', 'person'];
}

return ['Default', 'company'];
},
]);
}

In both of these cases, *only* the ``registration`` validation group will
be used to validate the underlying object. To apply the ``registration``
group *and* all constraints that are not in a group, use::
.. note::

Adding ``Default`` to the list of validation groups is common but not mandatory.
See the main :doc:`article about validation groups </validation/groups>` to
learn more about validation groups and the default constraints.

'validation_groups' => ['Default', 'registration']
You can also pass a static class method callback::

.. note::
'validation_groups' => [Client::class, 'determineValidationGroups']

Check failure on line 104 in form/validation_groups.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_DOUBLE_ARROW

Check failure on line 105 in form/validation_groups.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected EOF
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::

// 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::

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
----------

You can choose any name for your validation groups, but Symfony recommends
using "lower snake case" names (e.g. ``foo_bar``) in contrast with the
automatic validation groups created by Symfony, which use "upper camel case"
(e.g. ``Default``, ``SomeClassName``).
For more information about how validation groups work, see
:doc:`/validation/groups`.
2 changes: 0 additions & 2 deletions forms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1003,8 +1003,6 @@ Validation:
:maxdepth: 1

/form/validation_groups
/form/validation_group_service_resolver
/form/button_based_validation
/form/disabling_validation

Misc.:
Expand Down
Loading
Loading