如何在 symfony 5 中验证一些自定义约束

Posted

技术标签:

【中文标题】如何在 symfony 5 中验证一些自定义约束【英文标题】:How to validate some custom constraint in symfony 5 【发布时间】:2021-04-11 14:20:30 【问题描述】:

我有 Item 实体类,我必须验证它。我的条件是价格必须小于 1000。如果价格小于 5,库存小于 10,那也是错误的。所以对于第一个条件我使用 LessThan Constraint,但是对于第二个条件我应该怎么做呢?

class Item 
   /**
     * @ORM\Column(type="float")
     * @Assert\LessThan(self::ITEM_MAX_PRICE)
     */
    private float $price;

   /**
     * @ORM\Column(type="integer")
     */
    private int $stock;


如何验证这两个属性的第二个条件?

【问题讨论】:

symfony.com/doc/current/validation/custom_constraint.html 我已经读过这篇文章,但它是关于一个属性的验证,不是吗? 你也可以在类上放置断言。 换句话说,当你进入类时,你正在与对象(自定义验证器允许你访问)进行交互。 它是域,所以我个人建议这是应该在域代码中实现的逻辑。我添加了一个与我的项目类似的示例。 【参考方案1】:

不幸的是,Symfony 没有提供内置约束来验证它们之间的多个属性(顺便说一句,这样做和维护并不容易)。

我建议您查看Callback 约束,它可以灵活地验证您的实体。

但是,如果您的验证逻辑正在增长,我建议您使用custom validator。它是一项服务,因此您可以轻松地注入服务并对其进行测试。

【讨论】:

【参考方案2】:

我会使用自定义验证器。这是我的一个项目 (3.4) 中的一个示例。

三个文件:

<?php // src/AppBundle/Validator/Constraint/HasValidDimensions.php

namespace AppBundle\Validator\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class HasValidDimensions extends Constraint

    public $invalidWidth = 'Invalid width dimension.';
    public $invalidHeight = 'Invalid height dimension.';

    public function getTargets()
    
        return self::CLASS_CONSTRAINT;
    

注意CLASS_CONSTRAINT 的使用。现在,实际的验证器让我可以访问不同的部分(在这种情况下,它是一个命令验证器):

<?php // src/AppBundle/Validator/Constraint/HasValidDimensionsValidator.php

namespace AppBundle\Validator\Constraint;

use AppBundle\Message\Command\PageTemplate\SetPageTemplateDimensions;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * @Annotation
 */
class HasValidDimensionsValidator extends ConstraintValidator

    public function validate($setPageTemplateDimensions, Constraint $constraint): void
    
        /* @var SetPageTemplateDimensions $setPageTemplateDimensions */
        /* @var HasValidDimensions $constraint */

        $pageTemplate = $setPageTemplateDimensions->getPageTemplate();

        if ($setPageTemplateDimensions->getWidth() > $pageTemplate->getWidthReal()) 
            $this->context
                ->buildViolation($constraint->invalidWidth)
                ->addViolation()
            ;
        

        if ($setPageTemplateDimensions->getHeight() > $pageTemplate->getHeightReal()) 
            $this->context
                ->buildViolation($constraint->invalidHeight)
                ->addViolation()
            ;
        
    

然后在类上使用验证器:

<?php // src/AppBundle/Message/Command/PageTemplate/SetPageTemplateDimensions.php

namespace AppBundle\Message\Command\PageTemplate;

use AppBundle\Validator\Constraint as AppAssert;

/**
 * @AppAssert\HasValidDimensions()
 */
class SetPageTemplateDimensions implements TenantOwnedInterface

【讨论】:

【参考方案3】:

使用组序列可能很好并且很有用。在这种情况下,首先将检查价格是否小于,并且仅当第一个为真时才会检查另外两个断言 类似的东西:

   /** 
 * @Assert\GroupSequence("Item", "Strict") 
 */
class Item


   /** 
     * @ORM\Column(type="float")         
     * @Assert\LessThan(self::ITEM_MAX_PRICE) 
     * @Assert\GreaterThan(value=5, groups="Strict")
     */ 
     private float $price; 

   /** 
     * @Assert\GreaterThan(value=10, groups="Strict")
     * @ORM\Column(type="integer") 
     */ 
     private int $stock;

【讨论】:

不幸的是,它一个一个地检查条件,而不是一起检查:( 以这种方式制作带有类目标的自定义验证器可能会很好:)【参考方案4】:

所以,我认为你需要看看这个:https://medium.com/@gregurco.vlad/symfony-validation-trick-dependent-validation-eb48bc5e3d81

【讨论】:

以上是关于如何在 symfony 5 中验证一些自定义约束的主要内容,如果未能解决你的问题,请参考以下文章

基于其他约束的 Symfony 自定义验证器

对自定义 symfony 约束进行单元测试

Symfony2:如何对自定义复合表单类型使用约束?

API REST 的 symfony 5 自定义身份验证

Symfony 5 / 使用 API 编写自定义身份验证总是返回我无效的凭据

Symfony2 自定义身份验证:用户登录但未通过身份验证