是否可以验证模型类的属性依赖于同一类的另一个属性?
例如,我有这个类:
class Conference
{
/** $startDate datetime */
protected $startDate;
/** $endDate datetime */
protected $endDate;
}
我希望 Symfony 2.0 验证,$startDate
必须在$endDate
.
这可以通过注释实现还是我必须手动执行?
是否可以验证模型类的属性依赖于同一类的另一个属性?
例如,我有这个类:
class Conference
{
/** $startDate datetime */
protected $startDate;
/** $endDate datetime */
protected $endDate;
}
我希望 Symfony 2.0 验证,$startDate
必须在$endDate
.
这可以通过注释实现还是我必须手动执行?
从Symfony 2.4开始,您还可以使用表达式验证约束来实现您所需要的。我相信,这是最简单的方法。它肯定比回调约束更方便。
下面是如何使用验证约束注释更新模型类的示例:
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;
}
不要忘记在项目配置中启用注释。
您始终可以使用表达式语法进行更复杂的验证。
是的,回调验证器: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 字段上显示错误消息。
另一种方法(至少从Symfony 2.3开始)是使用 simple @Assert\IsTrue
:
class Conference
{
//...
/**
* @Assert\IsTrue(message = "Startime should be lesser than EndTime")
*/
public function isStartBeforeEnd()
{
return $this->getStartDate() <= $this->getEndDate;
}
//...
}
作为参考,文档.
从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
方法返回一个构建器,该构建器具有几个其他方法来帮助您配置约束(如参数和翻译)。
一个更好更干净的解决方案https://symfony.com/doc/3.4/validation/custom_constraint.html 是写
要检查实体是否正常,请添加到自定义约束(不是验证器)
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();
}
最好的部分是您需要在实体类中编写的内容:
use YourBundle\Validator\Constraints as YourAssert;
/**
* Yourentity
*
* @ORM\Table(name="yourentity")
* @ORM\Entity(repositoryClass="YourBundle\Repository\YourentityRepository")
*
* @YourAssert\YourConstraintClassName # <-- as simple as this
希望有帮助
对于日期验证,我们可以简单地使用 GreaterThan 和 GreaterThanOrEqual 比较约束。
class Conference
{
/**
* @var \DateTime
* @Assert\GreaterThanOrEqual("today")
*/
protected $startDate;
/**
* @var \DateTime
* @Assert\GreaterThan(propertyPath="startDate")
*/
protected $endDate;
}
有关详细信息,请参阅验证约束