mirror of
https://github.com/symfony/symfony-docs.git
synced 2026-03-24 00:32:14 +01:00
Merge branch '7.2' into 7.3
* 7.2: [Form][Validator] Merge all articles about using validation groups in forms
This commit is contained in:
@@ -576,3 +576,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
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
How to Choose Validation Groups Based on the Clicked Button
|
||||
===========================================================
|
||||
|
||||
When your form contains multiple submit buttons, you can change the validation
|
||||
group depending on which button is used to submit the form. For example,
|
||||
consider a form in a wizard that lets you advance to the next step or go back
|
||||
to the previous step. Also assume that when returning to the previous step,
|
||||
the data of the form should be saved, but not validated.
|
||||
|
||||
First, we need to add the two buttons to the form::
|
||||
|
||||
$form = $this->createFormBuilder($task)
|
||||
// ...
|
||||
->add('nextStep', SubmitType::class)
|
||||
->add('previousStep', SubmitType::class)
|
||||
->getForm();
|
||||
|
||||
Then, we configure the button for returning to the previous step to run
|
||||
specific validation groups. In this example, we want it to suppress validation,
|
||||
so we set its ``validation_groups`` option to false::
|
||||
|
||||
$form = $this->createFormBuilder($task)
|
||||
// ...
|
||||
->add('previousStep', SubmitType::class, [
|
||||
'validation_groups' => false,
|
||||
])
|
||||
->getForm();
|
||||
|
||||
Now the form will skip your validation constraints. 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.
|
||||
|
||||
.. seealso::
|
||||
|
||||
To see how to use a service to resolve ``validation_groups`` dynamically
|
||||
read the :doc:`/form/validation_group_service_resolver` article.
|
||||
@@ -1,72 +0,0 @@
|
||||
How to Choose Validation Groups Based on the Submitted Data
|
||||
===========================================================
|
||||
|
||||
If you need some advanced logic to determine the validation groups (e.g.
|
||||
based on submitted data), you can set the ``validation_groups`` option
|
||||
to an array callback::
|
||||
|
||||
use App\Entity\Client;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
// ...
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'validation_groups' => [
|
||||
Client::class,
|
||||
'determineValidationGroups',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
This will call the static method ``determineValidationGroups()`` on the
|
||||
``Client`` class after the form is submitted, but before validation is
|
||||
invoked. The Form object is passed as an argument to that method (see next
|
||||
example). You can also define whole logic inline by using a ``Closure``::
|
||||
|
||||
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 ['person'];
|
||||
}
|
||||
|
||||
return ['company'];
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
Using the ``validation_groups`` option overrides the default validation
|
||||
group which is being used. If you want to validate the default constraints
|
||||
of the entity as well you have to adjust the option as follows::
|
||||
|
||||
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'];
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
You can find more information about how the validation groups and the default constraints
|
||||
work in the article about :doc:`validation groups </validation/groups>`.
|
||||
@@ -1,58 +0,0 @@
|
||||
How to Dynamically Configure Form Validation Groups
|
||||
===================================================
|
||||
|
||||
Sometimes you need advanced logic to determine the validation groups. If they
|
||||
can't be determined by a callback, you can use a service. Create a service
|
||||
that implements ``__invoke()`` which accepts a ``FormInterface`` as a
|
||||
parameter::
|
||||
|
||||
// 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 apply and return an array
|
||||
|
||||
return $groups;
|
||||
}
|
||||
}
|
||||
|
||||
Then in your form, inject the resolver and set it as the ``validation_groups``::
|
||||
|
||||
// src/Form/MyClassType.php;
|
||||
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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
This will result in the form validator invoking your group resolver to set the
|
||||
validation groups returned when validating.
|
||||
@@ -1,19 +1,11 @@
|
||||
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>`::
|
||||
|
||||
$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::
|
||||
To define them when :ref:`creating forms in classes <creating-forms-in-classes>`,
|
||||
use the ``configureOptions()`` method::
|
||||
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
@@ -25,15 +17,147 @@ following to the ``configureOptions()`` method::
|
||||
]);
|
||||
}
|
||||
|
||||
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::
|
||||
When :ref:`creating forms in controllers <creating-forms-in-controllers>`, pass
|
||||
it as a form option::
|
||||
|
||||
'validation_groups' => ['Default', 'registration']
|
||||
$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::
|
||||
|
||||
[
|
||||
// ...
|
||||
'validation_groups' => ['Default', 'registration'],
|
||||
]
|
||||
|
||||
.. note::
|
||||
|
||||
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``).
|
||||
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' => 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 :doc:`article about validation groups </validation/groups>` to
|
||||
learn more about validation groups and the default constraints.
|
||||
|
||||
You can also pass a static class method callback::
|
||||
|
||||
'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::
|
||||
|
||||
// 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
|
||||
----------
|
||||
|
||||
For more information about how validation groups work, see
|
||||
:doc:`/validation/groups`.
|
||||
|
||||
@@ -995,8 +995,6 @@ Validation:
|
||||
:maxdepth: 1
|
||||
|
||||
/form/validation_groups
|
||||
/form/validation_group_service_resolver
|
||||
/form/button_based_validation
|
||||
/form/disabling_validation
|
||||
|
||||
Misc.:
|
||||
|
||||
@@ -1,59 +1,14 @@
|
||||
``validation_groups``
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**type**: ``array``, ``string``, ``callable``, :class:`Symfony\\Component\\Validator\\Constraints\\GroupSequence` or ``null`` **default**: ``null``
|
||||
**type**: ``array``, ``string``, ``callable``, :class:`Symfony\\Component\\Validator\\Constraints\\GroupSequence`, or ``null`` **default**: ``null``
|
||||
|
||||
This option is only valid on the root form and is used to specify which
|
||||
groups will be used by the validator.
|
||||
This option is only valid on the root form. It specifies which validation groups
|
||||
will be used by the validator.
|
||||
|
||||
For ``null`` the validator will just use the ``Default`` group.
|
||||
|
||||
If you specify the groups as an array or string they will be used by the
|
||||
validator as they are::
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'validation_groups' => 'Registration',
|
||||
]);
|
||||
}
|
||||
|
||||
This is equivalent to passing the group as array::
|
||||
|
||||
'validation_groups' => ['Registration'],
|
||||
|
||||
The form's data will be :doc:`validated against all given groups </form/validation_groups>`.
|
||||
|
||||
If the validation groups depend on the form's data a callable may be passed to
|
||||
the option. Symfony will then pass the form when calling it::
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
// ...
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'validation_groups' => function (FormInterface $form): array {
|
||||
$entity = $form->getData();
|
||||
|
||||
return $entity->isUser() ? ['User'] : ['Company'];
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can read more about this in :doc:`/form/data_based_validation`.
|
||||
|
||||
.. note::
|
||||
|
||||
When your form contains multiple submit buttons, you can change the
|
||||
validation group depending on :doc:`which button is used </form/button_based_validation>`
|
||||
to submit the form.
|
||||
|
||||
If you need advanced logic to determine the validation groups have
|
||||
a look at :doc:`/form/validation_group_service_resolver`.
|
||||
If set to ``null``, the validator will use only the ``Default`` group. For the
|
||||
other possible values, see the main article about
|
||||
:doc:`using validation groups in Symfony forms </form/validation_groups>`
|
||||
|
||||
In some cases, you want to validate your groups step by step. To do this, you
|
||||
can pass a :class:`Symfony\\Component\\Validator\\Constraints\\GroupSequence`
|
||||
|
||||
@@ -102,28 +102,8 @@ validation_groups
|
||||
**type**: ``array`` **default**: ``null``
|
||||
|
||||
When your form contains multiple submit buttons, you can change the validation
|
||||
group based on the button which was used to submit the form. Imagine a registration
|
||||
form wizard with buttons to go to the previous or the next step::
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
// ...
|
||||
|
||||
$form = $this->createFormBuilder($user)
|
||||
->add('previousStep', SubmitType::class, [
|
||||
'validation_groups' => false,
|
||||
])
|
||||
->add('nextStep', SubmitType::class, [
|
||||
'validation_groups' => ['Registration'],
|
||||
])
|
||||
->getForm();
|
||||
|
||||
The special ``false`` ensures that no validation is performed when the previous
|
||||
step button is clicked. When the second button is clicked, all constraints
|
||||
from the "Registration" are validated.
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can read more about this in :doc:`/form/data_based_validation`.
|
||||
group based on the clicked button. Read the article about
|
||||
:doc:`using validation groups in Symfony forms </form/validation_groups>`.
|
||||
|
||||
Form Variables
|
||||
--------------
|
||||
|
||||
Reference in New Issue
Block a user