如何动态控制表单的验证?

alt*_*aus 14 forms validation symfony symfony-2.5

我在Symfony的表单验证处理方面遇到了一些问题.我想基于其数据验证绑定到实体的表单.有很多信息如何使用FormEvents 动态修改表单字段.我在这个主题上缺少的是如何控制/修改验证.

我简化的用例是:

  1. 用户可以将事件添加到日历.
  2. 验证检查是否已有事件.
  3. 如果发生冲突,验证将引发错误.
  4. 用户现在应该能够忽略此错误/警告.

验证实现为ValidatorConstraint::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;
}
Run Code Online (Sandbox Code Playgroud)

验证器用作服务:

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

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

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

编辑3:正确声明约束.那不是问题:

services:
    validator.acme.date:
        class: AcmeBundle\Validator\Constraints\DateValidator
        arguments: ["@acme.other_service"]
        tags:
            - { name: validator.constraint_validator, alias: acme.validator.appointment.date }
Run Code Online (Sandbox Code Playgroud)

jua*_*nmf 2

验证是在实体上完成的,所有表单所做的就是执行对象的验证。您可以根据提交的数据选择组

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

我在嵌入式表单和级联验证上使用这种方法时遇到了问题

编辑:使用闪存来确定是否必须进行验证。

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