yuchimiriのブログ

ぺちぱーです。

Symfony2でカスタムバリデータを作る3ステップ

こんにちはyuchimiriです。

このブログはSymfony Advent Calendar JP 2011 8日目の記事です。
昨日の担当はmadapajaさんでした。


去年のAdvent Calendarでは「SymfonyEventDispatcher→Symfony2(PR4)EventDispatcherの変更点」という記事を書いたのですが、今年はもう少し実践的なものを書きたいな…ということでSymfony2でのカスタムバリデータの作成方法についてご紹介します。


Symfony2では、Symfony\Component\Validator\ConstraintクラスとSymfony\Component\Validator\ConstraintValidatorクラスを拡張して独自のバリデータを作ることができます。


今回は簡単な例として、テキストエリアに改行区切りで入力された文字列がすべて日付であることをチェックするバリデータを4ステップで作ってみます。
(フォームなどは既に用意してある前提です。)


1. 任意のディレクトリ内に、Symfony\Component\Validator\Constraintクラスを継承した制約クラスを作成
vi src/Acme/DemoBundle/Validator/DatesCollection.php

<?php

namespace Acme\DemoBundle\Validator;

use Symfony\Component\Validator\Constraint;

/**
 * Date collection.
 *
 */
class DateCollection extends Constraint
{
    public $emptyMessage = '入力は必須です';
    public $message = '日付でないものが含まれています';
}


3. Symfony\Component\Validator\ConstraintValidatorクラスを継承したバリデーションクラスを作成

vi src/Acme/DemoBundle/Validator/DatesCollectionValidator.php

<?php

namespace Acme\DemoBundle\Validator;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Constraints\Date;
use Symfony\Component\Validator\Constraints\DateValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

/**
 * Date collection validator.
 *
 */
class DateCollectionValidator extends ConstraintValidator
{
    /**
     * {@inheritDoc}
     */
    public function isValid($value, Constraint $constraint)
    {

        $dates = array_filter(array_map('trim', explode("\n", $value)));

        if (count($dates) < 1) {
            $this->setMessage($constraint->emptyMessage);

            return false;
        }

        $dateConstraint = new Date(array('message' => $constraint->message));
        $dateValidator = new DateValidator($this->context);

        foreach ($dates as $date) {
            if (false === $dateValidator->isValid(str_replace('/', '-', $date), $dateConstraint)) {
                $this->setMessage($dateValidator->getMessageTemplate(), $dateValidator->getMessageParameters());

                return false;
            }
        }

        return true;
    }
}


3. 作成した制約クラスを使うように、validation.ymlに設定
vi src/Acme/DemoBundle/Resources/config/validation.yml

namespaces:
    Demo: Acme\DemoBundle\Validator\

Acme\DemoBundle\Data\Dates:
    properties:
        dates:
            - Demo:DateCollection: ~

Symfonyはここで設定した制約クラス(DateCollection)を見て、「制約クラス名+Validator」という名前のクラスを探し、その中のisValid()メソッドを使ってバリデーションを行います。


ちょっと複雑なバリデーションをしたいときでも簡単に作れそうですね。


明日のAdventCallendarは@Kiskeさんです。