Как применить только подмножество всех ваших ограничений валидации (группы валидации)

Как применить только подмножество всех ваших ограничений валидации (группы валидации)

По умолчанию, при валидации объекта, все ограничения этого класса будут проверены на предмет того, действительно ли они подойдут. Однако, в некоторых случаях, вам понадобится валидировать объект только по отношению к некоторым ограничениям этого класса. Чтобы сделать это, вы можете организовать каждое ограничение в одну или более "групп валидации", а потом применить валидацию только к одной группе ограничений.

Например, представьте, что у вас есть класс User, который используется как при регистрации пользователя, так и при обновлении контактной информации позже:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // src/AppBundle/Entity/User.php
    namespace AppBundle\Entity;
    
    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Validator\Constraints as Assert;
    
    class User implements UserInterface
    {
        /**
         * @Assert\Email(groups={"registration"})
         */
        private $email;
    
        /**
         * @Assert\NotBlank(groups={"registration"})
         * @Assert\Length(min=7, groups={"registration"})
         */
        private $password;
    
        /**
         * @Assert\Length(min=2)
         */
        private $city;
    }
    
  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    # src/AppBundle/Resources/config/validation.yml
    AppBundle\Entity\User:
        properties:
            email:
                - Email: { groups: [registration] }
            password:
                - NotBlank: { groups: [registration] }
                - Length: { min: 7, groups: [registration] }
            city:
                - Length:
                    min: 2
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <!-- src/AppBundle/Resources/config/validation.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://symfony.com/schema/dic/constraint-mapping
            http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd
        ">
    
        <class name="AppBundle\Entity\User">
            <property name="email">
                <constraint name="Email">
                    <option name="groups">
                        <value>registration</value>
                    </option>
                </constraint>
            </property>
    
            <property name="password">
                <constraint name="NotBlank">
                    <option name="groups">
                        <value>registration</value>
                    </option>
                </constraint>
                <constraint name="Length">
                    <option name="min">7</option>
                    <option name="groups">
                        <value>registration</value>
                    </option>
                </constraint>
            </property>
    
            <property name="city">
                <constraint name="Length">
                    <option name="min">7</option>
                </constraint>
            </property>
        </class>
    </constraint-mapping>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // src/AppBundle/Entity/User.php
    namespace AppBundle\Entity;
    
    use Symfony\Component\Validator\Mapping\ClassMetadata;
    use Symfony\Component\Validator\Constraints as Assert;
    
    class User
    {
        public static function loadValidatorMetadata(ClassMetadata $metadata)
        {
            $metadata->addPropertyConstraint('email', new Assert\Email(array(
                'groups' => array('registration'),
            )));
    
            $metadata->addPropertyConstraint('password', new Assert\NotBlank(array(
                'groups' => array('registration'),
            )));
            $metadata->addPropertyConstraint('password', new Assert\Length(array(
                'min'    => 7,
                'groups' => array('registration'),
            )));
    
            $metadata->addPropertyConstraint('city', new Assert\Length(array(
                "min" => 3,
            )));
        }
    }
    

В такой конфигурации существует три группы валидации:

Default
Содержит ограничения в текущем классе и все упомянутые классы, которые не принадлежат ни к одной другой группе.
User
Эквивалентна всем ограничениям объекта User в группе Default. Это всегда является именем класса. Разица между этой группой и Default объясняется ниже.
registration
Содержит ограничения только полей email и password.

Ограничения в группе класса Default - это ограничения, которые либо не имеют явной сконфигурированной группы, или которые сконфигурированы в группу, равную имени класса или строке Default.

Caution

При валидации только объекта пользователя (User), не существует разницы между группами Default и User. Но разница существует, если User имеет встроенные объекты. Например, представьте, что User имеет свойство address, которое содержит некоторый объект Address, и что вы добавили ограничение Valid к этому свойству, чтобы оно было валидировано при валидации объекта User.

Если вы валидируете User. используя группу Default, то любые ограничения в классе Address, которые находятся в группе Default будут использованы. Но, если вы валидируете User, используя группу валидации User, тогда будут валидированы только ограничения класса Address.

Другими словами, группа Default и группа класса имени (например, User) идентичны, кроме случаев, когда класс встрое в другой объект, чем тот, валидация которого проводится.

Если у вас есть наследование (например, User extends BaseUser) и вы валидируете с классом имени подкласса (т.е. User), то все ограничения в User и BaseUser будут валидированы. Однако, если вы валидируете, используя базовый класс (т.е. BaseUser), то будут валидированы только ограничения по умолчанию в классе BaseUser.

Чтобы сообщить валидатору об использовании конкретной группы, передайте одно или более имён групп в качестве третьего аргумента метода validate():

1
$errors = $validator->validate($author, null, array('registration'));

Если не указана ни одна группа, будут применены все ограничения, принадлежащие группе Default

Конечно же, вы чаще будете работать с валидацией не напрямую, а через библиотеку форм. Для информации о том, как использовать группы валидации внутри форм, смотрите How to Define the Validation Groups to Use.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.