【问题标题】:Symfony validator with dependencies具有依赖关系的 Symfony 验证器
【发布时间】:2023-06-24 11:05:01
【问题描述】:

我想用约束注解验证一个对象,并在验证器上使用依赖项(entityManager)。

验证器不起作用,如果它在构造函数中有依赖项(例如 entityManager)。

我遵循了文档,但它不起作用: https://symfony.com/doc/current/validation/custom_constraint.html#constraint-validators-with-dependencies

"ClassNotFoundException 尝试从全局命名空间加载类“validator_question_exists”。 您是否忘记了“使用”声明?”

我尝试像这样验证“问题”对象(也许这就是问题所在):

$validator = Validation::createValidatorBuilder()
    ->enableAnnotationMapping()
    ->getValidator()
;

$question = new Question();
$errors = $validator->validate($question);

问题(要验证的对象)

/** @App\Validator\Constraint\Question\QuestionExists() */
class QuestionReadInput{
    ....
}

services.yaml

services:
    validator.unique.question_exists:
        class: App\Validator\Constraint\Question\QuestionExistsValidator
        tags:
            - { name: validator.constraint_validator, alias: validator_question_exists}

约束

namespace App\Validator\Constraint\Question;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class QuestionExists extends Constraint
{
    public $message;

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }

    public function validatedBy()
    {
        //if i delete this function, symfony cant autowire the entitymanager to the validator
        //this throws an error, wants to make a new validator_question_exists(), which not exists, because its a service alias, the docs said it should be okay
        return 'validator_question_exists';
    }
}

验证器

class QuestionExistsValidator extends ConstraintValidator
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function validate($value, Constraint $constraint)
    {
          die('I dont see this message...');
    }

调试:容器


Information for Service "validator.unique.question_exists"
 ---------------- -------------------------------------------------------------------
  Option           Value
 ---------------- -------------------------------------------------------------------
  Service ID       validator.unique.question_exists
  Class            App\Validator\Constraint\Question\QuestionExistsValidator
  Tags             validator.constraint_validator (alias: validator_question_exists)
                   validator.constraint_validator
  Public           no
  Synthetic        no
  Lazy             no
  Shared           yes
  Abstract         no
  Autowired        yes
  Autoconfigured   yes

【问题讨论】:

  • 我认为您的验证器标签应该是:tags: ['validator.constraint_validator'] 并完成它。还要删除validatedBy,因为它会使用你别名的validator.constraint_validator,这根本没有任何意义。您本可以使用validator.unique.question_exists(适当的验证器),但删除它会导致类名被附加并查找Validator。如果它在同一个命名空间中,它应该可以工作。
  • 更改了标签格式(但我认为没关系),尝试使用validatedBy return 'validator.unique.question_exists',得到与上面相同的'classNotFound exception'。是的,验证器位于同一个命名空间中,类名后附加了“验证器”。如果我删除了 validBy 类,仍然无法自动装配 entitymanager:“函数 App\Validator\Constraint\Question\QuestionExistsValidator::__construct() 的参数太少,0 传入 /var/www.../web/vendor/symfony /validator/ConstraintValidatorFactory.php 位于第 43 行,预期正好为 1"
  • 您能解释一下为什么您自己创建Validator 实例而不是使用Symfony 提供的validator 服务吗?
  • 正如 xabbuh 所说,自己构建验证器可能会产生错误,validatedBy 方法显然必须返回验证器的 类名,而不是服务描述符。

标签: php symfony validation symfony4 symfony-3.4


【解决方案1】:

我刚刚使用了默认的 symfony 验证器,正如 @xabbuh 所提到的,它起作用了。

__construct(ValidatorInterface $validator){
    $question = new Question();
    $errors   = $validator->validate($question);
}

我不应该使用 Validaton::createValidatorBuilder 创建自己的验证器。

如果你使用这个配置也没关系:

App\Validator\Constraint\Question\QuestionExistsValidator:
    tags: ['validator.constraint_validator']

with no validatedBy()

或者那个:

validator.unique.question_exists:
    class: App\Validator\Constraint\Question\QuestionExistsValidator
    tags:
        - { name: validator.constraint_validator, alias: validator_question_exists}

with:

public function validatedBy() {
    return 'validator_question_exists';
}

【讨论】:

    【解决方案2】:

    如果您自己声明服务,那么您还应该添加它的参数:

    services:
        validator.unique.question_exists:
            class: App\Validator\Constraint\Question\QuestionExistsValidator
            arguments: ['@doctrine.orm.entity_manager']
            tags:
                - { name: validator.constraint_validator }
    

    除此之外,它应该在没有任何标签别名或validatedBy 方法的情况下工作。

    旁注:很长一段时间以来,在 Symfony 中,建议通过类名来命名(id)您的服务,这样自动连接可以处理您的服务,并且您不需要类参数,即:

    services:
        App\Validator\Constraint\Question\QuestionExistsValidator:
            arguments: ['@doctrine.orm.entity_manager']
            tags:
                - { name: validator.constraint_validator }
    

    【讨论】: