如何在Symfony 2中验证依赖于另一个属性的属性

时间:2012-09-04 09:39:13

标签: validation symfony

是否可以验证依赖于同一类的另一个属性的模型类的属性?

例如,我有这个课程:

class Conference
{
    /** $startDate datetime */
    protected $startDate;

    /** $endDate datetime */
    protected $endDate;
}

我希望Symfony 2.0验证,$startDate必须在$endDate之后。

这可以通过注释来实现,还是我必须手动执行此操作?

6 个答案:

答案 0 :(得分:36)

Symfony 2.4 开始,您还可以使用Expression验证约束来实现您的需求。我相信,这是最简单的方法。它确实比Callback约束更方便。

以下是如何使用验证约束注释更新模型类的示例:

use Symfony\Component\Validator\Constraints as Assert;


class Conference
{
    /**
     * @var \DateTime
     *
     * @Assert\Expression(
     *     "this.startDate <= this.endDate",
     *     message="Start date should be less or equal to end date!"
     * )
     */
    protected $startDate;

    /**
     * @var \DateTime
     *
     * @Assert\Expression(
     *     "this.endDate >= this.startDate",
     *     message="End date should be greater or equal to start date!"
     * )
     */
    protected $endDate;
}

不要忘记项目配置中的enable annotations

您可以使用expression syntax始终进行更复杂的验证。

答案 1 :(得分:20)

是的回调验证器:http://symfony.com/doc/current/reference/constraints/Callback.html

关于symfony 2.0:

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

/**
 * @Assert\Callback(methods={"isDateValid"})
 */
class Conference
{

    // Properties, getter, setter ...

    public function isDateValid(ExecutionContext $context)
    {
        if ($this->startDate->getTimestamp() > $this->endDate->getTimestamp()) {
                $propertyPath = $context->getPropertyPath() . '.startDate';
                $context->setPropertyPath($propertyPath);
                $context->addViolation('The starting date must be anterior than the ending date !', array(), null);
        }
    }
}

在symfony主版本上:

    public function isDateValid(ExecutionContext $context)
    {
        if ($this->startDate->getTimestamp() > $this->endDate->getTimestamp()) {
            $context->addViolationAtSubPath('startDate', 'The starting date must be anterior than the ending date !', array(), null);
        }
    }

这里我选择在startDate字段上显示错误消息。

答案 2 :(得分:10)

另一种方式(至少与 Symfony 2.3 一样)是使用简单的@Assert\IsTrue

class Conference
{
    //...

    /**
     * @Assert\IsTrue(message = "Startime should be lesser than EndTime")
     */
    public function isStartBeforeEnd()
    {
        return $this->getStartDate() <= $this->getEndDate;
    }

    //...
}

作为参考,documentation

答案 3 :(得分:9)

version 2.4以来,它变得更加简单。您所要做的就是将此方法添加到您的班级:

use Symfony\Component\Validator\Context\ExecutionContextInterface;

/**
 * @Assert\Callback
 */
public function isStartBeforeEnd(ExecutionContextInterface $context)
{
    if ($this->getStartDate() <= $this->getEndDate()) {
        $context->buildViolation('The start date must be prior to the end date.')
                ->atPath('startDate')
                ->addViolation();
    }
}

buildViolation method返回一个构建器,其中包含其他一些方法来帮助您配置约束(如参数和转换)。

答案 4 :(得分:2)

更好更清洁的解决方案https://symfony.com/doc/3.4/validation/custom_constraint.html 就是写

  • 自定义约束(基本上是错误消息)
  • 及其验证器(类似于执行控制的控制器功能

要检查实体是否正常,请添加到自定义约束(不是验证器)

protected void configure(HttpSecurity http) throws Exception {
    http.logout()                                                                
        .logoutUrl("/my/logout")                                                 
        .logoutSuccessUrl("/my/index")                                           
        .logoutSuccessHandler(logoutSuccessHandler)                              
        .invalidateHttpSession(true)                                             
        .addLogoutHandler(logoutHandler)                                         
        .deleteCookies(cookieNamesToClear)                                       
        .and()
        ...

}

允许您使用该实体的实例,而不仅仅是属性值。这样就可以在验证器中编写:

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

最好的部分是您需要在实体类中编写的内容:

public function validate($object, Constraint $constraint)
{
    #Your logic, for example:
    if($value1 = $object->getValue1())
    {
        if($value2 = $object->getValue2())
        {
            if($value1 === $value2)
            {
                # validation passed
                return True;
            }
            else
            {
                # validation failed
                $this->context->buildViolation($constraint->message)
                    ->setParameter('{{ string }}', $value1.' !== '.$value2)
                    ->addViolation();
            }

希望有帮助

答案 5 :(得分:0)

对于日期验证,我们可以简单地使用GreaterThan和GreaterThanOrEqual比较约束。

├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── hellokoding
│       │           └── hello
│       │               └── web
│       │                   └── YourClass.java
│       ├── resources
│       │   ├── application.properties
│       │   └── logback.xml
│       └── webapp
│           ├── resources
│           │   ├── css
│           │   │   └── bootstrap.min.css
│           │   ├── images
│           │   └── js
│           │       └── bootstrap.min.js
│           └── WEB-INF
│               ├── views
│               │   └── hello.jsp
|               ├── appconfig-mvc.xml
│               ├── appconfig-root.xml 
│               └── web.xml 
└── pom.xml

有关更多信息,请参见validation constraints