Callback

Дата обновления перевода 2023-01-14

Callback

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

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

Note

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

??????????? ? ?????? ??? ????????/??????
????? Callback
????????? CallbackValidator

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

  • Attributes
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Entity/Author.php
namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class Author
{
    #[Assert\Callback]
    public function validate(ExecutionContextInterface $context, $payload)
    {
        // ...
    }
}

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

Методу обратного вызова передаётся специальный объект 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 = [/* ... */];

    // проверить, является ли имя действительно фальшивым
    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)
    {
        // ...
    }
}

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

  • Attributes
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
// src/Entity/Author.php
namespace App\Entity;

use Acme\Validator;
use Symfony\Component\Validator\Constraints as Assert;

#[Assert\Callback([Validator::class, 'validate'])]
class Author
{
}

Note

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

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

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

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

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

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

Warning

Использование Closure вместе с конфигурацией атрибута отключит кеш атрибута для этого класса/свойства/метода, потому что Closure нельзя кешировать. Для наилучшей производительности, рекомендуется использовать метод статичного обратного вызова.

Опции

callback

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

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

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

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

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

groups

type: array | string

It defines the validation group or groups of this constraint. Read more about validation groups.

payload

тип: mixed по умолчанию: null

Эта опция может быть использована, чтобы добавить к ограничению произвольные данные, относящиеся к домену. Сконфигурированная нагрузка не используется компонентом Валидатор, но его обработка полностью зависит от вас.

Например, вы можете захотеть исользовать несколько уровней ошибок, чтобы представить неудачные ограничения в фронт-энде по-разному, в зависимости от степени сложности ошибки.