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

Joh*_*auß 28 validation symfony

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

例如,我有这个类:

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

    /** $endDate datetime */
    protected $endDate;
}
Run Code Online (Sandbox Code Playgroud)

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

这可能是注释还是我必须手动执行此操作?

Sla*_* II 36

Symfony 2.4开始,您还可以使用表达式验证约束来实现您的需求.我相信,这是最简单的方法.它确实比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;
}
Run Code Online (Sandbox Code Playgroud)

不要忘记在项目配置中启用注释.

您始终可以使用表达式语法执行更复杂的验证.


Syb*_*bio 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

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


Dam*_*nic 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;
    }

    //...
}
Run Code Online (Sandbox Code Playgroud)

作为参考,文档.


Taz*_*Taz 9

版本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();
    }
}
Run Code Online (Sandbox Code Playgroud)

buildViolation方法返回一个构建器,该构建器具有其他几种方法来帮助您配置约束(如参数和转换).


nic*_*ias 5

更好更干净的解决方案https://symfony.com/doc/3.4/validation/custom_constraint.html 是编写

  • 自定义约束(基本上是错误消息)
  • 及其验证器(就像一个控制器函数,负责控制

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

public function getTargets()
{
    return self::CLASS_CONSTRAINT;
}
Run Code Online (Sandbox Code Playgroud)

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

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();
            }
Run Code Online (Sandbox Code Playgroud)

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

use YourBundle\Validator\Constraints as YourAssert;

/**
 * Yourentity
 *
 * @ORM\Table(name="yourentity")
 * @ORM\Entity(repositoryClass="YourBundle\Repository\YourentityRepository")
 *
 * @YourAssert\YourConstraintClassName # <-- as simple as this
Run Code Online (Sandbox Code Playgroud)

希望有帮助