Symfony 4/5中的自定义验证基础与示例

在我看来,在Symfony中,这是一种非常方便的用于实体验证的功能。特别是,使用注释格式配置验证规则确实使我受贿。在绝大多数任务中,交钥匙解决方案涵盖标准案例。但是,正如您所知,验证是一件微妙的事情,您永远都不知道这次必须施加什么限制。另一方面,更灵活,经过深思熟虑的验证将始终有助于避免用户错误。


在摘要中,我邀请您查看使用基本验证和验证示例编写限制并扩展两个可用字段的比较是多么容易。那些对Symfony中的验证还是不太熟悉的人,或者已经绕过编写自己的验证器的可能性的人,可能会感兴趣。


在本文中,我们将牢记经典的验证环境。有一个特定的实体,其数据从相应的表格中填写,而验证对输入数据的任何方面都施加了限制。值得注意的是,验证器可以不受限制地用于控制内部逻辑,API验证等。


我们立即确定,提出的示例不是唯一可能的解决方案,并且不要求最大的最优性或广泛使用,而只是出于演示目的。另一方面,部分示例是从战斗项目中提取并简化的,我希望这些示例可用于说明编写自定义验证的简单性,而不会干扰现实。


基本验证


为了进行完整的功能验证,您只需要创建两个类-Constraint和ConstraintValidator的继承者。顾名思义,约束定义并描述约束,而ConstraintValidator对其进行验证。举例来说,我们将以文本格式存储的时间格式为“ hh:mm”的形式编写验证器。官方文档中,建议“约束”描述约束的公共属性。因此,让我们开始吧。


namespace App\Custom\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 * @Target({"PROPERTY"})
 */
class TextTime extends Constraint
{
    public $message = '  ';
}

在这里,Target批注确定是对属性还是对类使用验证。您也可以通过覆盖功能来设置此参数。


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

您可能会猜到,message属性用于显示有关验证错误的信息。


, .


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

, , ConstraintValidator. ConstraintValidator validate.


namespace App\Custom\Constraints;

use Symfony\Component\Validator\ConstraintValidator;

class TextTimeValidator extends ConstraintValidator
{
    /**
     *    
     *
     * @param mixed $value  
     * @param Constraint $constraint   
     */
    public function validate($value, Constraint $constraint)
    {
        $time = explode(':', $value);

        $hours = (int) $time[0];
        $minutes = (int) $time[1];

        if ($hours >= 24 || $hours < 0)
            $this->fail($constraint);
        else if ((int) $time[1] > 60 || $minutes < 0)
            $this->fail($constraint);
    }

    private function fail(Constraint $constraint) 
    {
        $this->context->buildViolation($constraint->message)
            ->addViolation();
    }
}

, , , .


...
    /**
     * @Assert\NotBlank()
     * @Assert\Regex(
     *     pattern="/\d{2}:\d{2}/",
     *     message=" "
     * )
     * @CustomAssert\TextTime()
     * @ORM\Column(type="string", length=5)
     */
    private $timeFrom;
...

, , . , , , message .


. , Symfony Time. : . , "hh:mm:ss". , .



, , - . , , : "hh:mm", "hh:mm"-"hh:mm". , , .


, AbstractComparsion. AbstractComparsion Constraint — .


namespace App\Custom\Constraints;

use Symfony\Component\Validator\Constraints\AbstractComparison;

/**
 * @Annotation
 * @Target({"PROPERTY"})
 */
class TextTimeInterval extends AbstractComparison
{   
    public $message = '       {{ compared_value }}.';
}


namespace App\Custom\Constraints;

use Symfony\Component\Validator\Constraints\AbstractComparisonValidator;

class TextTimeIntervalValidator extends AbstractComparisonValidator
{
    /**
     *       
     *
     * @param mixed $timeFrom   
     * @param mixed $timeTo   
     *
     * @return  true   , false 
     */
    protected function compareValues($timeFrom, $timeTo)
    {
        $compareResult = true;

        $from = explode(':', $timeFrom);
        $to = explode(':', $timeTo);

        try {
            if ((int) $from[0] > (int) $to[0])
                $compareResult = false;
            else if (((int) $from[0] == (int) $to[0]) && ((int) $from[1] > (int) $to[1])) {
                $compareResult = false;
            }
        } catch (\Exception $exception) {
            $compareResult = false;
        }

        return $compareResult;
    }
}

仅在这种情况下(可能的实现之一),我们才覆盖compareValues函数,该函数在验证成功时返回true / false,并由validate()函数在AbstractComparisonValidator中进行处理。


基本上描述如下


...
 /**
     * @Assert\NotBlank()
     * @Assert\Regex(
     *     pattern="/\d{2}:\d{2}/",
     *     message=" "
     * )
     * @CustomAssert\TextTime()
     * @CustomAssert\TextTimeInterval(
     *     propertyPath="timeTo",
     *     message="       "
     * )
     * @ORM\Column(type="string", length=5)
     */
    private $timeFrom;

    /**
     * @Assert\NotBlank()
     * @Assert\Regex(
     *     pattern="/\d{2}:\d{2}/",
     *     message=" "
     * )
     * @CustomAssert\TextTime()
     * @ORM\Column(type="string", length=5)
     */
    private $timeTo;
...

希望这个小小的分析和例子表明了使用自定义验证器是多么容易。当然,由于对于初学者来说,我们考虑了最简单的验证器,因此,为了不使演示文稿的主题描述过于繁琐,我们无法提供出色的示例。在以后的文章中,我计划考虑更复杂的验证器和特定案例。


All Articles