我在Symfony的表单验证处理方面遇到了一些问题。我想基于其数据验证绑定到实体的表单。有很多信息如何使用dynamically modify 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 }
答案 0 :(得分:2)
验证在实体上完成,所有Forms都执行Object的验证。 你可以choose groups based on submitted data
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => function(FormInterface $form) {
$data = $form->getData();
if (Entity\Client::TYPE_PERSON == $data->getType()) {
return array('person');
} else {
return array('company');
}
},
));
}
我在嵌入式表格和&&amp ;;上使用这种方法时遇到了问题。 cascade-validation
编辑:使用Flash确定是否必须进行验证。
// service definition
<service id="app.form.type.callendar" class="%app.form.type.callendar.class%">
<argument type="service" id="session" />
<tag name="form.type" alias="my_callendar" />
</service>
// some controller
public function somAvtion()
{
$form = $this->get('app.form.type.callendar');
...
}
// In the form
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => function(FormInterface $form) {
$session = $form->getSession();
if ($session->getFlashBag()->get('callendar_warning', false)) {
return array(false);
} else {
return array('Validate_callendar');
}
},
));
}
答案 1 :(得分:0)
您的用户如何与应用程序交互以告知其忽略警告?是否有某种额外的按钮?
在这种情况下,您只需检查用于提交表单的按钮或添加某种隐藏字段(ignore_validation
)等。
无论你最终从哪里获得用户输入(闪存和依赖注入,基于提交的数据等),我都会使用验证组和闭包来确定要验证的内容(就像在{{3中所解释的juanmf一样) }})。
RE第二种方法(表单事件),您可以为事件侦听器添加优先级:正如您在his answer中看到的那样,他们使用FormEvents::POST_SUBMIT
来启动验证过程。因此,如果您只是添加一个事件侦听器,它将在验证侦听器之前调用,因此尚未进行验证。
如果您向侦听器添加否定优先级,则应该还能够访问表单验证错误:
$builder->addEventListener(FormEvents::POST_SUBMIT, function(){...}, -900);
答案 2 :(得分:0)
老问题但是......
我会先按照您的建议和上面的其他答案添加一个字段(acceptCollision)。
然后验证者可以执行以下操作:
public function validate($appointment, Constraint $constraint)
{
if (null === $date = $appointment->getDate()) {
return;
}
if ($appointment->getAcceptCollision()) {
$valid = true;
} elseif (
// Check Unicity of the date (no collision)
) {
$valid = true;
} else {
$valid = false;
}
if (!$valid) {
$this->context->addViolationAt('date', $constraint->message);
}
}
答案 3 :(得分:0)
我认为你遇到了一个问题,因为你使用了错误的概念。验证应该运行的决定属于控制器,而不是验证器。
所以我只需在控制器中检查按下提交按钮(或者是否选中了复选框)并切换验证组。但是表单应该在视觉上不同,所以我可能会为两个状态创建两个表单(都扩展一个基本的或一个使用选项的表单类型)。