|
1 |
| -How to Define the Validation Groups to Use |
2 |
| -========================================== |
| 1 | +Configuring Validation Groups in Forms |
| 2 | +====================================== |
3 | 3 |
|
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. |
6 | 6 |
|
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:: |
10 | 22 |
|
11 | 23 | $form = $this->createFormBuilder($user, [
|
12 | 24 | 'validation_groups' => ['registration'],
|
13 | 25 | ])->add(/* ... */);
|
14 | 26 |
|
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 | + ] |
17 | 35 |
|
| 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; |
18 | 79 | use Symfony\Component\OptionsResolver\OptionsResolver;
|
19 | 80 |
|
20 | 81 | public function configureOptions(OptionsResolver $resolver): void
|
21 | 82 | {
|
22 | 83 | $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 | + }, |
25 | 93 | ]);
|
26 | 94 | }
|
27 | 95 |
|
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. |
31 | 101 |
|
32 |
| - 'validation_groups' => ['Default', 'registration'] |
| 102 | +You can also pass a static class method callback:: |
33 | 103 |
|
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 | +---------- |
35 | 161 |
|
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`. |
0 commit comments