Callback

Цель ограниченися Обратного вызова (Callback) - создать полностью пользовательские правила валидации и назначить любые ошибки валидации конкретным полям вашего объекта. Если вы используете валидацию с формами, это означает, что можете сделать так, чтобы эти пользовательские ошибки отображались рядом с конкретным полем, а не просто наверху вашей формы.

Этот процесс работает путём указания одного или больше методов обратного вызова, каждый из которых будет вызван во время процесса валидации. Каждый из этих методов может сделать что угодно, включая создание и назначение ошибок валидации.

Note

Метод обратного вызова сам по себе не может быть неудачным или вернуть какое-либо значение. Вместо этого, как вы увидите в примере, метод обратного вызова имеет способность напрямую добавить "нарушения" валидатора.

Применяется к классу
Опции
Класс Callback
Валидатор CallbackValidator

Конфигурация

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // src/AppBundle/Entity/Author.php
    namespace AppBundle\Entity;
    
    use Symfony\Component\Validator\Constraints as Assert;
    use Symfony\Component\Validator\Context\ExecutionContextInterface;
    
    class Author
    {
        /**
         * @Assert\Callback
         */
        public function validate(ExecutionContextInterface $context, $payload)
        {
            // ...
        }
    }
    
  • YAML
    1
    2
    3
    4
    # src/AppBundle/Resources/config/validation.yml
    AppBundle\Entity\Author:
        constraints:
            - Callback: validate
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <!-- 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\Author">
            <constraint name="Callback">validate</constraint>
        </class>
    </constraint-mapping>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    // src/AppBundle/Entity/Author.php
    namespace AppBundle\Entity;
    
    use Symfony\Component\Validator\Mapping\ClassMetadata;
    use Symfony\Component\Validator\Constraints as Assert;
    
    class Author
    {
        public static function loadValidatorMetadata(ClassMetadata $metadata)
        {
            $metadata->addConstraint(new Assert\Callback('validate'));
        }
    }
    

Метод обратного вызова

Методу обратного вызова передаётся специальный объект ExecutionContextInterface. Вы можете установить "нарушения" прямо в этом объекте и определить, к какому полю должны быть приписаны эти ошибки:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// ...
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class Author
{
    // ...
    private $firstName;

    public function validate(ExecutionContextInterface $context, $payload)
    {
        // каим-то образом у вас есть массив "фальшивых имён"
        $fakeNames = array(/* ... */);

        // проверить, является ли имя действительно фальшивым
        if (in_array($this->getFirstName(), $fakeNames)) {
            $context->buildViolation('This name sounds totally fake!')
                ->atPath('firstName')
                ->addViolation();
        }
    }
}

Статические обратные вызовы

Вы также можете использовать ограничение со статическими методами. Так как статические методы не имеют доступа к экземпляру объекта, они получают объект в качестве первого аргумента:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public static function validate($object, ExecutionContextInterface $context, $payload)
{
    // каим-то образом у вас есть массив "фальшивых имён"
    $fakeNames = array(/* ... */);

    // проверить, является ли имя действительно фальшивым
    if (in_array($object->getFirstName(), $fakeNames)) {
        $context->buildViolation('This name sounds totally fake!')
            ->atPath('firstName')
            ->addViolation()
        ;
    }
}

Внешние обратные вызовы и замыкания

Если вы хотите выполнить статичный метод обратного вызова, который не находится в классе валидируемого объекта, вы можете сконфигурировать ограничение так, чтобы оно запускало вызываемое массива, как это поддерживается PHP-функцией call_user_func. Представьте, что ваша функция валидации - Acme\Validator::validate():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
namespace Acme;

use Symfony\Component\Validator\Context\ExecutionContextInterface;

class Validator
{
    public static function validate($object, ExecutionContextInterface $context, $payload)
    {
        // ...
    }
}

Потом вы можете использовать следующую конфигурацию для вызова этого валидатора:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // src/AppBundle/Entity/Author.php
    namespace AppBundle\Entity;
    
    use Symfony\Component\Validator\Constraints as Assert;
    
    /**
     * @Assert\Callback({"Acme\Validator", "validate"})
     */
    class Author
    {
    }
    
  • YAML
    1
    2
    3
    4
    # src/AppBundle/Resources/config/validation.yml
    AppBundle\Entity\Author:
        constraints:
            - Callback: [Acme\Validator, validate]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- 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\Author">
            <constraint name="Callback">
                <value>Acme\Validator</value>
                <value>validate</value>
            </constraint>
        </class>
    </constraint-mapping>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    // src/AppBundle/Entity/Author.php
    namespace AppBundle\Entity;
    
    use Acme\Validator;
    use Symfony\Component\Validator\Mapping\ClassMetadata;
    use Symfony\Component\Validator\Constraints as Assert;
    
    class Author
    {
        public static function loadValidatorMetadata(ClassMetadata $metadata)
        {
            $metadata->addConstraint(new Assert\Callback(array(
                Validator::class,
                'validate',
            )));
        }
    }
    

Note

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// src/AppBundle/Entity/Author.php
namespace AppBundle\Entity;

use Symfony\Component\Validator\Context\ExecutionContextInterface;

use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $callback = function ($object, ExecutionContextInterface $context, $payload) {
            // ...
        };

        $metadata->addConstraint(new Assert\Callback($callback));
    }
}

Опции

callback

тип: string, array или Closure [опция по умолчанию]

Опция обратного вызова принимает три разных формата для указания метода обратного вызова:

  • Строка, содержащая имя конкретного или статичного метода;
  • Вызываемое массива в формате array('<Class>', '<method>');
  • Замыкание.

Конкретные обратные вызовы получают экземпляр ExecutionContextInterface в качестве единственного аргумента.

Статичные или замыкающие обратные вызовы получают валидированный объект в качестве первого аргумента, а экземпляр ExecutionContextInterface - в качестве второго.

payload

type: mixed default: null

This option can be used to attach arbitrary domain-specific data to a constraint. The configured payload is not used by the Validator component, but its processing is completely up to you.

For example, you may want to use several error levels to present failed constraints differently in the front-end depending on the severity of the error.

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