Callback
Callback 约束的目的是创建完全自定义的验证规则,并将任何验证错误分配给对象上的特定字段。如果将验证与表单一起使用,这意味着您可以将自定义错误显示在它们适用的字段旁边,而不是在表单顶部显示自定义错误。
此过程通过指定一个或多个 callback 方法来实现,每个方法将在验证过程中被调用。这些方法中的每一个都可以执行任何操作,包括创建和分配验证错误。
注意
callback 方法本身不会失败或返回任何值。相反,正如您将在示例中看到的那样,callback 方法能够直接添加验证器“违规”。
适用于 | 类 或 属性/方法 |
类 | Callback |
验证器 | CallbackValidator |
配置
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, mixed $payload): void
{
// ...
}
}
Callback 方法
callback 方法被传递一个特殊的 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 string $firstName;
public function validate(ExecutionContextInterface $context, mixed $payload): void
{
// somehow you have an array of "fake names"
$fakeNames = [/* ... */];
// check if the name is actually a fake name
if (in_array($this->getFirstName(), $fakeNames)) {
$context->buildViolation('This name sounds totally fake!')
->atPath('firstName')
->addViolation();
}
}
}
静态 Callback
您还可以将约束与静态方法一起使用。由于静态方法无法访问对象实例,因此它们将对象作为第一个参数接收
1 2 3 4 5 6 7 8 9 10 11 12 13
public static function validate(mixed $value, ExecutionContextInterface $context, mixed $payload): void
{
// somehow you have an array of "fake names"
$fakeNames = [/* ... */];
// check if the name is actually a fake name
if (in_array($value->getFirstName(), $fakeNames)) {
$context->buildViolation('This name sounds totally fake!')
->atPath('firstName')
->addViolation()
;
}
}
外部 Callback 和闭包
如果您想执行不在已验证对象类中的静态 callback 方法,您可以配置约束以调用 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(mixed $value, ExecutionContextInterface $context, mixed $payload): void
{
// ...
}
}
然后,您可以使用以下配置来调用此验证器
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
{
}
注意
Callback 约束不支持全局 callback 函数,也不可能将全局函数或服务方法指定为 callback。要使用服务进行验证,您应该创建一个自定义验证约束并将该新约束添加到您的类中。
通过 PHP 配置约束时,您还可以将闭包传递给 Callback 约束的构造函数
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): void
{
$callback = function (mixed $value, ExecutionContextInterface $context, mixed $payload): void {
// ...
};
$metadata->addConstraint(new Assert\Callback($callback));
}
}
警告
将 Closure
与属性配置一起使用将禁用该类/属性/方法的属性缓存,因为 Closure
无法缓存。为了获得最佳性能,建议使用静态 callback 方法。
选项
callback
类型: string
、array
或 Closure
[默认选项]
callback 选项接受三种不同的格式来指定 callback 方法
- 一个 string,其中包含具体方法或静态方法的名称;
- 格式为
['<Class>', '<method>']
的数组可调用方法; - 一个闭包。
具体 callback 接收 ExecutionContextInterface 实例作为第一个参数,payload 选项作为第二个参数。
静态或闭包 callback 接收已验证的对象作为第一个参数,ExecutionContextInterface 实例作为第二个参数,payload 选项作为第三个参数。