オープンソースこねこね

Webプログラミングなどについてあれこれ。

Laravelのバリデーション拡張を作った

LaravelでWebアプリを書いていて、ややバリデーション周りの機能が薄いと感じたので拡張パッケージを書きました。

LaravelValidatorExtension

Laravel標準のバリデーションについては公式のドキュメントを見ればいいかと思います。この場合Validator::makeメソッドに入力データ、バリデーションルール、デフォルトから変える必要があるならエラー時のメッセージ、をそれぞれ配列で渡してvalidatorオブジェクトを作成し、その後failsメソッドで検証が通るかどうかを確認します。例えば以下のようなコードになります。

<?php
$rules = array(
    'username' => 'required|alpha',
    'password' => 'required|alpha|min:8',
);

$validator = Validator::make(Input::all(), $rules);

if ($validator->fails()) {
    return Redirect::back()->withErrors($validator);
}

シンプルなのはいいのですが、実際のアプリケーションを書くとなると更に以下のようなことがしたくなります。

  • バリデーションルールの定義箇所をメインロジックから個別のクラスに外出ししたい。
  • バリデーションの前後で値の変換処理を行いたい。例えばバリデーションの前に値をtrimしたり年月日で個別のフィールドに入力された値を結合して日付形式にするなど。

このへんの仕組みが標準では用意されていなかったので、前述の拡張を書きました。

使い方

バリデータクラスをこんな感じに定義して。。。

<?php
// app/validators/BlogValidator.php
class BlogValidator extends BaseValidator
{
    protected function configure()
    {
        $this
            ->rule('title', 'required', 'Title is required.')
            ->rule('title', 'max:100', 'Title must not be greater than 100 characters.')
            ->rule('body', 'pass')
            ;
    }
}

以下のように使います。

<?php
$validator = BlogValidator::make(Input::all());
if ($validator->fails()) {
    return Redirect::back()->withInput(Input::all())->withErrors($validator);
}

$data = $validator->onlyValidData();

バリデーション定義がメインロジックから切りだされてスッキリ。

また$validator->onlyValidDataメソッドはバリデートが行われた項目の値のみを配列で戻すメソッドなので、DB更新時などはこの値をEloquentモデルのマスアサインメントでまるっと設定してやればいいかと思います。

フィルタとカスタムバリデーションルール

バリデーション前後に何らかの処理を入れたいときはbeforeFilterafterFilterクロージャを登録します。

<?php
class BlogValidator extends BaseValidator
{
    protected function configure()
    {
        $this->beforeFilter(function($validator){
            // your code
        });

        $this->afterFilter(function($validator){
            // Modify title after validation.
            $title = $validator->title;
            $title .= " created by kohki";
            $validator->title = $title;
        });
    }
}

独自のバリデーションルールを定義したいときはvalidateXXXというメソッドを作ればOKです。メソッドの規約は標準のカスタムバリデーションルールの定義方法を同じですので、公式ドキュメントを参考にしてください。

<?php
class BlogValidator extends BaseValidator
{
    protected function configure()
    {
        $this
            ->rule('title', 'required', 'Title is required.')
            ->rule('title', 'max:100', 'Title must not be greater than 100 characters.')
            ->rule('body', 'foo', 'Body must be foo only!')
            ;
    }

    protected function validateFoo($attribute, $value, $parameters)
    {
        return $value == 'foo';
    }
}

インストール方法

composerでインストールします。composer.jsonに以下を記述して

"require": {
    "kohkimakimoto/laravel-validator-extension": "0.*"
}

composer updateします。

$ composer update

ServiceProviderとBaseValidatorのエイリアスapp/config/app.phpに登録します。

'providers' => array(
    ...
    'Kohkimakimoto\ValidatorExtension\ValidatorExtensionServiceProvider',
}
'aliases' => array(
    ...
    'BaseValidator' => 'Kohkimakimoto\ValidatorExtension\Validator',
),

また、私は今のところapps/validatorsディレクトリを切ってそこに個々のバリデータクラスを作成しているので、オートロードされるようにLaravel(app/start/global.php)とcomposer(composer.json)にオートロード設定を追加します。

ClassLoader::addDirectories(array(
    ...
    app_path().'/validators',
));
"autoload": {
    "classmap": [
        ...
        "app/validators"
    ]
}

Laravelかわいいよ、Laravelヽ(´ー`)ノ