Skip to content

Commit 38d2041

Browse files
committed
Merge branch '6.4' into 7.2
* 6.4: [Form][Validator] Merge all articles about using validation groups in forms
2 parents 7ef1b3f + 47a16e9 commit 38d2041

File tree

8 files changed

+155
-261
lines changed

8 files changed

+155
-261
lines changed

_build/redirection_map

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,6 @@
576576
/components/serializer /serializer
577577
/serializer/custom_encoder /serializer/encoders#serializer-custom-encoder
578578
/components/string /string
579+
/form/button_based_validation /form/validation_groups
580+
/form/data_based_validation /form/validation_groups
581+
/form/validation_group_service_resolver /form/validation_groups

form/button_based_validation.rst

Lines changed: 0 additions & 36 deletions
This file was deleted.

form/data_based_validation.rst

Lines changed: 0 additions & 72 deletions
This file was deleted.

form/validation_group_service_resolver.rst

Lines changed: 0 additions & 58 deletions
This file was deleted.

form/validation_groups.rst

Lines changed: 144 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,163 @@
1-
How to Define the Validation Groups to Use
2-
==========================================
1+
Configuring Validation Groups in Forms
2+
======================================
33

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

7-
If your object takes advantage of :doc:`validation groups </validation/groups>`,
8-
you'll need to specify which validation group(s) your form should use. Pass
9-
this as an option when :ref:`creating forms in controllers <creating-forms-in-controllers>`::
7+
To define them when :ref:`creating forms in classes <creating-forms-in-classes>`,
8+
use the ``configureOptions()`` method::
9+
10+
use Symfony\Component\OptionsResolver\OptionsResolver;
11+
12+
public function configureOptions(OptionsResolver $resolver): void
13+
{
14+
$resolver->setDefaults([
15+
// ...
16+
'validation_groups' => ['registration'],
17+
]);
18+
}
19+
20+
When :ref:`creating forms in controllers <creating-forms-in-controllers>`, pass
21+
it as a form option::
1022

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

15-
When :ref:`creating forms in classes <creating-forms-in-classes>`, add the
16-
following to the ``configureOptions()`` method::
27+
In both cases, *only* the ``registration`` group will be used to validate the
28+
object. To apply the ``registration`` group *and* all constraints not in any
29+
other group, add the special ``Default`` group::
30+
31+
[
32+
// ...
33+
'validation_groups' => ['Default', 'registration'],
34+
]
1735

36+
.. note::
37+
38+
You can use any name for your validation groups. Symfony recommends using
39+
"lower snake case" (e.g. ``foo_bar``), while automatically generated
40+
groups use "UpperCamelCase" (e.g. ``Default``, ``SomeClassName``).
41+
42+
Choosing Validation Groups Based on the Clicked Button
43+
------------------------------------------------------
44+
45+
When your form has :doc:`multiple submit buttons </form/multiple_buttons>`, you
46+
can change the validation group based on the clicked button. For example, in a
47+
multi-step form like the following, you might want to skip validation when
48+
returning to a previous step::
49+
50+
$form = $this->createFormBuilder($task)
51+
// ...
52+
->add('nextStep', SubmitType::class)
53+
->add('previousStep', SubmitType::class)
54+
->getForm();
55+
56+
To do so, configure the validation groups of the ``previousStep`` button to
57+
``false``, which is a special value that skips validation::
58+
59+
$form = $this->createFormBuilder($task)
60+
// ...
61+
->add('previousStep', SubmitType::class, [
62+
'validation_groups' => false,
63+
])
64+
->getForm();
65+
66+
Now the form will skip your validation constraints when that button is clicked.
67+
It will still validate basic integrity constraints, such as checking whether an
68+
uploaded file was too large or whether you tried to submit text in a number field.
69+
70+
Choosing Validation Groups Based on Submitted Data
71+
--------------------------------------------------
72+
73+
To determine validation groups dynamically based on submitted data, use a
74+
callback. This is called after the form is submitted, but before validation is
75+
invoked. The callback receives the form object as its first argument::
76+
77+
use App\Entity\Client;
78+
use Symfony\Component\Form\FormInterface;
1879
use Symfony\Component\OptionsResolver\OptionsResolver;
1980

2081
public function configureOptions(OptionsResolver $resolver): void
2182
{
2283
$resolver->setDefaults([
23-
// ...
24-
'validation_groups' => ['registration'],
84+
'validation_groups' => function (FormInterface $form): array {
85+
$data = $form->getData();
86+
87+
if (Client::TYPE_PERSON === $data->getType()) {
88+
return ['Default', 'person'];
89+
}
90+
91+
return ['Default', 'company'];
92+
},
2593
]);
2694
}
2795

28-
In both of these cases, *only* the ``registration`` validation group will
29-
be used to validate the underlying object. To apply the ``registration``
30-
group *and* all constraints that are not in a group, use::
96+
.. note::
97+
98+
Adding ``Default`` to the list of validation groups is common but not mandatory.
99+
See the main :doc:`article about validation groups </validation/groups>` to
100+
learn more about validation groups and the default constraints.
31101

32-
'validation_groups' => ['Default', 'registration']
102+
You can also pass a static class method callback::
33103

34-
.. note::
104+
'validation_groups' => [Client::class, 'determineValidationGroups']
105+
106+
Choosing Validation Groups via a Service
107+
----------------------------------------
108+
109+
If validation group logic requires services or can't fit in a closure, use a
110+
dedicated validation group resolver service. The class of this service must
111+
be invokable and receives the form object as its first argument::
112+
113+
// src/Validation/ValidationGroupResolver.php
114+
namespace App\Validation;
115+
116+
use Symfony\Component\Form\FormInterface;
117+
118+
class ValidationGroupResolver
119+
{
120+
public function __construct(
121+
private object $service1,
122+
private object $service2,
123+
) {
124+
}
125+
126+
public function __invoke(FormInterface $form): array
127+
{
128+
$groups = [];
129+
130+
// ... determine which groups to return
131+
132+
return $groups;
133+
}
134+
}
135+
136+
Then use the service in your form type::
137+
138+
namespace App\Form;
139+
140+
use App\Validation\ValidationGroupResolver;
141+
use Symfony\Component\Form\AbstractType;
142+
use Symfony\Component\OptionsResolver\OptionsResolver;
143+
144+
class MyClassType extends AbstractType
145+
{
146+
public function __construct(
147+
private ValidationGroupResolver $groupResolver,
148+
) {
149+
}
150+
151+
public function configureOptions(OptionsResolver $resolver): void
152+
{
153+
$resolver->setDefaults([
154+
'validation_groups' => $this->groupResolver,
155+
]);
156+
}
157+
}
158+
159+
Learn More
160+
----------
35161

36-
You can choose any name for your validation groups, but Symfony recommends
37-
using "lower snake case" names (e.g. ``foo_bar``) in contrast with the
38-
automatic validation groups created by Symfony, which use "upper camel case"
39-
(e.g. ``Default``, ``SomeClassName``).
162+
For more information about how validation groups work, see
163+
:doc:`/validation/groups`.

forms.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -995,8 +995,6 @@ Validation:
995995
:maxdepth: 1
996996

997997
/form/validation_groups
998-
/form/validation_group_service_resolver
999-
/form/button_based_validation
1000998
/form/disabling_validation
1001999

10021000
Misc.:

0 commit comments

Comments
 (0)