【问题标题】:Syfmony custom validator based on other Constraints基于其他约束的 Symfony 自定义验证器
【发布时间】:2020-10-16 03:31:53
【问题描述】:

如何编写自定义验证器?

例如,我有这个工作代码:


use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\Validation;



        $input = [
            null,   //fail
            0,      //fail
            1,      //fail
            2,      //fail
            "12",   //ok - string can be (at least 2 chars)
            20,     //ok
            50      //ok
        ];

        $constraint = new Assert\All([
            // the keys correspond to the keys in the input array
            new Assert\NotBlank(),
            new Assert\AtLeastOneOf([
                new Assert\Sequentially([
                    new Assert\Type(['type' => 'int']),
                    new Assert\GreaterThanOrEqual(20)
                ]),
                new Assert\Sequentially([
                    new Assert\Type(['type' => 'string']),
                    new Assert\Length(2)
                ])
            ])
        ]);

        $validator = Validation::createValidator();

        $violations = $validator->validate($input, $constraint);

我想将“检查”打包到一个类中,例如:


        $input = [
            null,   //fail
            0,      //fail
            1,      //fail
            2,      //fail
            "12",   //ok - string can be (at least 2 chars)
            20,     //ok
            50      //ok
        ];

        $constraint = new Assert\All(
            new IdConstraint()
        );

        $validator = Validation::createValidator();

        $violations = $validator->validate($input, $constraint);


IdContrains 或 IdValidator 类应该是什么样子?这是我到目前为止得到的:

namespace App\Constraint;

use Symfony\Component\Validator\Constraint;

class IdConstraint extends Constraint
{
    public $message = 'The input "{{ string }}" contains invalid values.';
}
namespace App\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class IdValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        //what to put here???
    }
}

提前致谢!

【问题讨论】:

  • 输入你的逻辑并在逻辑被破坏时添加违规。还有 rtfm symfony.com/doc/current/validation/custom_constraint.html
  • 我已经阅读了调频,但我不知道该把逻辑放在哪里?我已经发布了工作逻辑,但不确定如何将其集成到 IdValidator 类中。这就是我寻求帮助的原因。
  • 逻辑在validate 方法中。用$value 做任何你想做的事。如果出现问题 - 向 this->context 添加/构建违规。

标签: php symfony validation


【解决方案1】:

我找到了以下解决方案:


namespace App\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class GroupValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        $context = $this->context;

        $validator = $context->getValidator();
        $validations = $validator->validate($value, $constraint->getConstraints());

        if ($validations->count() > 0) {
            $this->context->buildViolation($constraint->message)
                ->setParameter('{{ value }}', (string)$value)
                ->addViolation();
        }
    }
}
<?php

namespace App\Constraint;

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

/**
 * @Annotation
 */
class IdConstraint extends Constraint
{
    public $message = 'The input "{{ value }}" contains invalid values.';

    public function validatedBy()
    {
        return GroupValidator::class;
    }

    public function getConstraints()
    {
        return [
            new Assert\NotBlank(),
            new Assert\AtLeastOneOf([
                new Assert\Sequentially([
                    new Assert\Type(['type' => 'int']),
                    new Assert\GreaterThanOrEqual(20)
                ]),
                new Assert\Sequentially([
                    new Assert\Type(['type' => 'string']),
                    new Assert\Length(2)
                ])
            ])
        ];
    }
}

在测试代码中:

        $input = [
            null,   //fail
            0,      //fail
            1,      //fail
            2,      //fail
            "12",   //ok - string can be (at leas 2 chars)
            20,     //ok
            50      //ok
        ];

        $constraint = new Assert\All(
            new IdConstraint()
        );

作为替代方案,我看到在 Symfony 5.1 中,使用 compound 是可能的,但我无法在那里设置一个简单的错误消息。

<?php

namespace App\Constraint;

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

/**
 * @Annotation
 */
class IdConstraint1 extends Compound
{
    protected function getConstraints(array $options): array
    {
        return [
            new Assert\NotBlank(),
            new Assert\AtLeastOneOf([
                new Assert\Sequentially([
                    new Assert\Type(['type' => 'int']),
                    new Assert\GreaterThanOrEqual(20)
                ]),
                new Assert\Sequentially([
                    new Assert\Type(['type' => 'string']),
                    new Assert\Length(2)
                ])
            ])
        ];
    }
}

【讨论】:

    【解决方案2】:

    您没有指定您使用的 Symfony 版本,但如果您有 maker 包,创建验证器的最简单方法是 php bin/console make:validator

    作为您的验证代码,您没有提供很多细节,但根据我从您的代码中了解到的情况,您的验证可能是这样的。

    namespace App\Constraint;
    
    use Symfony\Component\Validator\Constraint;
    use Symfony\Component\Validator\ConstraintValidator;
    
    class IdValidator extends ConstraintValidator
    {
        public function validate($value, Constraint $constraint)
        {
            $value = (int) $value;
    
            if ($value < 10) {
                $this->context->buildViolation($constraint->message)
                    ->setParameter('{{ value }}', $value)
                    ->addViolation();
            }
        }
    }
    

    【讨论】:

    • 我想使用其他约束来验证我的 Id 值。逻辑在问题中,也许我描述得不够好。我已经发布了我现在创建的解决方案的答案,并且似乎运行良好。当然欢迎改进:)
    • 是的,我在你自己的解决方案中看到了,我没有理解正确
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    • 2017-12-04
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    相关资源
    最近更新 更多