Symfony2のバリデーションについて

アプリケーションを開発していくうえでカスタムバリデーションを作るまでもないけど、
独自のバリデーションを追加したかったり、動的にバリデーションを行いたいことがよくある。
Symfony2ではどのように行うのかメモっておく。

例えばお問い合わせフォームなどで、利用規約の同意にチェックが入っていないと送信できないようにしたい。
この例の場合、フォームクラスは下記のようになる。

<?php
namespace Sample\Bundle\DemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

use Symfony\Component\Form\CallbackValidator;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;

class ContactType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name', 'text')
            ->add('email', 'email')
            ->add('body', 'textarea')
            ->add('terms', 'checkbox', array('property_path' => false))
        ;

        $builder->addValidator(new CallbackValidator(function(FormInterface $form) {
            if (!$form['terms']->getData()) {
                $form['terms']->addError(new FormError('利用規約に同意してないと送信できないよ'));
            }
        }));
    }

    public function getName()
    {
        return 'contact';
    }
}

termsのオプションでproperty_pathをfalseにすることによって、Entityクラスに依存しなくなる。
で、addValidatorにCallbackValidator経由でクロージャを登録することによって独自のバリデーションを行えるようになる。

コントローラに書くことも出来るけど、コントローラがあまり複雑になるのはよくないので、フォームクラスで簡潔させたほうがスマートだと思う。


【参考ページ】

  1. http://fivestar.hatenablog.com/entry/2011/12/06/013145
  2. http://www.richsage.co.uk/2011/07/20/adding-non-entity-fields-to-your-symfony2-forms/