【Symfony】動的にバリデーションを追加する方法

addEventListener を使うことで動的にバリデーションを追加することができる。

createFormBuildercreateForm にエンティティを渡していない、もしくはエンティティにないプロパティに対してバリデーションをかけたい場合や、特定の条件を満たす場合にのみバリデーションをかけたい場合などに使えるかも。

例えば以下は、開始時刻と終了時刻を入力するケースで、終了時刻が開始時刻以降になっているかどうかをチェックしている。

<?php
// ...
class HogeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, [
                // ...
            ])
            ->add('startTime', DateTimeType::class, [
                // ...
            ])
            ->add('endTime', DateTimeType::class, [
                // ...
            ])
            ->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
                $form = $event->getForm();
                if ($form['startTime']->getData() > $form['endTime']->getData()) {
                    $form['endTime']->addError(new FormError('開始時刻以降を指定してください'));
                }
            })
        ;
    }
}

他にも、利用規約のチェックがついているかどうかを確かめたり。

<?php
// ...
class HogeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, [
                // ...
            ])
            ->add('agreement', CheckboxType::class, [
                // ...
            ])
            ->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
                $form = $event->getForm();
                if(!$form->has('agreement')){
                    $form->addError(new FormError('利用規約に同意してください'));
                }
            })
        ;
    }
}

注意点

Symfony2.2以前では addValidator が使えていた

<?php
// ...
$builder->addValidator(new CallbackValidator(function($form) {
    // ...
}));

この書き方はSymfony2.1で非推奨となり、Symfony2.3からは完全に使えなくなっている。
ググって調べるとこの方法も見つかるが、使用するときはSymfonyのバージョンに注意する。