我在 Symfony 的表单验证处理方面遇到了一些问题。我想根据其数据验证绑定到实体的表单。有很多关于如何使用FormEvents动态修改表单字段的信息。我在这个主题上缺少的是如何控制/修改验证。
我的简化用例是:
- 用户可以将事件添加到日历。
- 验证检查是否已经存在事件。
- 如果发生冲突,验证将引发错误。
- 用户现在应该能够忽略此错误/警告。
验证是作为目标实现Validator
的Constraint::CLASS_CONSTRAINT
(因为它考虑了更多的东西)。
我尝试过了:
- 绕过验证组,但无法访问实体范围的验证器。
- 破解
FormEvents
并添加一个额外的字段,例如“忽略日期警告”。 - 绕过提交按钮将其更改为“强制提交”之类的内容。
...但从未找到有效的解决方案。使用基于单个属性的验证器进行更简单的黑客攻击也无法奏效。:(
有没有一种 Symfony 方法来动态控制验证?
编辑:我的代码如下所示:
use Doctrine\ORM\Mapping as ORM;
use Acme\Bundle\Validator\Constraints as AcmeAssert;
/**
* Appointment
*
* @ORM\Entity
* @AcmeAssert\DateIsValid
*/
class Appointment
{
/**
* @ORM\Column(name="title", type="string", length=255)
*
* @var string
*/
protected $title;
/**
* @ORM\Column(name="date", type="date")
*
* @var \DateTime
*/
protected $date;
}
用作服务的验证器:
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the date of an appointment.
*/
class DateIsValidValidator extends ConstraintValidator
{
/**
* {@inheritdoc}
*/
public function validate($appointment, Constraint $constraint)
{
if (null === $date = $appointment->getDate()) {
return;
}
/* Do some magic to validate date */
if (!$valid) {
$this->context->addViolationAt('date', $constraint->message);
}
}
}
对应的Constraint
类被设置为以实体类为目标。
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class DateIsValid extends Constraint
{
public $message = 'The date is not valid!';
/**
* {@inheritdoc}
*/
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
/**
* {@inheritdoc}
*/
public function validatedBy()
{
return 'acme.validator.appointment.date';
}
}
编辑2:尝试FormEvents
...我也尝试了所有不同的事件。
$form = $formFactory->createBuilder()
->add('title', 'text')
->add('date', 'date')
->addEventListener(FormEvents::WHICHONE?, function(FormEvent $event) {
$form = $event->getForm();
// WHAT TO DO HERE?
$form->getErrors(); // Is always empty as all events run before validation?
// I need something like
if (!$dateIsValid) {
$form->setValidationGroup('ignoreWarning');
}
});
编辑 3:正确声明了约束。那不是问题:
services:
validator.acme.date:
class: AcmeBundle\Validator\Constraints\DateValidator
arguments: ["@acme.other_service"]
tags:
- { name: validator.constraint_validator, alias: acme.validator.appointment.date }