首页 > 解决方案 > 如何将实例传递给 symfony 表单验证器类?

问题描述

我正在尝试创建一个自定义 symfony 表单验证器约束。我创建了两个类,一个约束和一个验证器,它工作正常。但是我需要将学说 entitymanager 实例传递给验证器类,因为我是独立使用它们而不是框架,我没有 yaml 配置文件。我在验证器类中创建了一个构造函数来拥有 $em,并且在控制器中我有:

->add('email', EmailType::class, [                                              
    'constraints' => [
        new Assert\Email(['message' => 'invalid.email', 'mode' => 'strict', 'normalizer' => 'trim']),
        new Assert\EmailExists($em),
    ],
 ]);

但是我没有得到 $em,在我的验证器类中,我该怎么办?我还尝试在主约束类中使用构造函数,然后在验证器中使用parent::construct(),但仍然无法正常工作。

我也读过这篇文章 How to configure dependencies on custom validator with Symfony Components?但是我没有创建工厂类,而是使用了当前的因子类并使用了这个:

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Validator\ContainerConstraintValidatorFactory;

$container = new ContainerBuilder();
$container
    ->register('customEmailUniqueEntity', 'EmailExistsValidator')
    ->addArgument($em);
$validatorBuilder = Validation::createValidatorBuilder();
$validatorBuilder->setConstraintValidatorFactory(
    new ContainerConstraintValidatorFactory($container)
);

$validator = $validatorBuilder->getValidator();
$violations = $validator->validate('email address', [ 
    new EmailExists() 
]);

if (0 !== count($violations)) {
    // there are errors, now you can show them
    foreach ($violations as $violation) {
        echo $violation->getMessage().'<br>';
    }
}

使用此代码,依赖注入和验证都可以正常工作,但是有没有技巧可以将此自定义约束作为表单构建器中的“约束”数组参数而不是手动验证?

->add('email', EmailType::class, [                                              
    'constraints' => [
        new Assert\Email(['message' => 'invalid.email', 'mode' => 'strict', 'normalizer' => 'trim']),
        new Assert\EmailExists($em),
    ],
 ]);

使用上面的代码,我无法将 $em 传递给我的自定义验证器的构造函数。有什么技巧可以吗?

编辑:

为了注入学说EntityManager,在EmailExists课堂上我有:

 public function validatedBy()
 {
        return 'customEmailUniqueEntity';
        //return \get_class($this).'Validator';
 }

然后我有:

$container = new ContainerBuilder();
$container
    ->register('customEmailUniqueEntity', 'EmailExistsValidator')
    ->addArgument($em);

因为如果我从那里返回验证器类,validatedBy()我无法将 $em 注入验证器的构造函数。有了下面的答案,我使用了:

->addTag('validator.constraint_validator');

但是现在我收到customEmailUniqueEntityclass not found 错误,好像我从 中返回验证器validatedBy(),注入将不起作用,我该怎么办?我试图返回

 public function validatedBy()
 {
        return 'EmailExists';
        //return \get_class($this).'Validator';
 }

但是这个,我当然会initialize()出错。请指教。

编辑2:

我将 addTag 添加到:

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Validator\ContainerConstraintValidatorFactory;

$container = new ContainerBuilder();
$container
    ->register('customEmailUniqueEntity', 'EmailExistsValidator')
    ->addArgument($em),
    ->addTag('validator.constraint_validator');

$validatorBuilder = Validation::createValidatorBuilder();
$validatorBuilder->setConstraintValidatorFactory(
    new ContainerConstraintValidatorFactory($container)
);

$validator = $validatorBuilder->getValidator();
$violations = $validator->validate('email address', [ 
    new EmailExists() 
]);

if (0 !== count($violations)) {
    // there are errors, now you can show them
    foreach ($violations as $violation) {
        echo $violation->getMessage().'<br>';
    }
}

在 EmailExistsValidator 的构造函数中,我有:

var_dump($em);

我在验证器中得到了 $em 对象,所以 $em 被注入并且添加addTag()没有导致任何错误。如果我取消约束,则不会进行注入validatedBy()EmailExists在我正在做的那种方法中

return `customEmailUniqueEntity;`

因为如果我返回EmailExistsValidator,注射将不会完成。现在如何使用validator.constraint_validatorEmailExists()作为约束形式的数组参数?如果我使用new EmailExists(),我将获得两个验证器类的 Aguments,因为 $em 不会以这种方式注入。该怎么办?

标签: phpsymfonysymfony4

解决方案


当确定要用于约束的实际验证器时,您的customEmailUniqueEntity服务将永远不会被考虑在内。ContainerConstraintValidatorFactoryEmailExists

为了让工厂知道哪些服务是约束验证器,您需要使用如下标签对其进行validator.constraint_validator标记:

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;

$container = new ContainerBuilder();
$container
    ->register('customEmailUniqueEntity', 'EmailExistsValidator')
    ->addArgument($em)
    ->addTag('validator.constraint_validator');
$container->addCompilerPass(new AddConstraintValidatorPass());
$container->compile();

推荐阅读