[FuelPHP]Validationの使い方



FuelPHP Advent Calendar 2011 : ATND

先日、@kenji_sさんからFuelPHPのAdvent Calendarがあるから良かったらどうぞということだったので、参加してみることにしました。Advent Calendar初参加!

とは言うもののCodeIgniterは仕事でも使っていたのですが、FuelPHPは一切触ったことがないというくらい初めてのもので、そんな自分にでも何か書ける内容がないかと探して、ほとんどのシステムで必要になるであろうValidation部分について調べながら書くことにしました。そのため、いくつか間違っている点などがあるかもしれませんが、もしそういう点がありましたら、コメントなり何なり頂けると助かります。

広告

では、早速基本的なValidationの使い方を見ていきたいと思います。

いきなりですが、Validationのドキュメントについては、こちらになります。

基本的な検証

今回は、「ユーザ名」、「メールアドレス」という2つの入力項目に対しての入力値の検証処理を書いてみたいと思います。

検証部分

検証テスト用のController_Validationというコントローラを作成し、入力値を検証するメソッドとして、action_validateの処理を下記のようにしてみました。

// 1. Validationオブジェクト生成
$validation = Validation::forge();
 
// 2. 検証ルール設定
// 2.1. username項目の検証ルール設定
$validation->add('username', 'ユーザ名')
    ->add_rule('required')
    ->add_rule('mix_length', 4)
    ->add_rule('max_length', 10);
 
// 2.2. email項目の検証ルール設定
$validation->add_field('email', 'メールアドレス', 'required|min_length[10]|max_length[128]');
 
// 3. 検証実行
if ($validation->run()) {
    // 3.1. 検証成功
    return Response::forge(View::forge('validation/index'));
} else {
    // 3.2. 検証失敗
    return Response::forge(View::forge('validation/index'));
}

まず、「1. Validationオブジェクト生成」の箇所ですが、Validation#forgeメソッドは、フィールドセットと呼ばれる、入力ソースのグループだと個人的には捉えているのですが、そのグループの名前を引数に渡すことができます。グループが1つしかない場合は未指定(デフォルト:default)、グループが2つ以上なるような複雑な場合には、名前を指定して、複数のValidationオブジェクトを生成、管理することも出来ます。

例えば、バッチ等で1リクエスト中に複数の外部リソースを取り込む場合に、それらの値の検証を行う場合に複数のValidationオブジェクトが使えると便利です。

次に、2.1, 2.2で検証ルールを設定していますが、add_ruleのようにチェインメソッド形式で指定する方法と、CodeIgniterのように一度に全て設定する方法があります。

また、デフォルトで提供されている検証ルールはこちらに記載されています。

で、最後の「3. 検証実行」の部分で検証ルールに基づいて検証を実行しています。

エラー表示

$errors = $validation->error(); // エラーの項目とメッセージの連想配列を取得
$error_html = $validation->show_errors(); // エラーメッセージ用HTMLを取得
$error_input = $validation->input(); // 検証に使用した入力値を項目と値の連想配列で取得

のように、Fuel\Core\Validation#show_errorsメソッドを使うことで、エラーメッセージ用のHTML文字列を返してくれます。

ただし、FuelPHPでは標準でView内で使用される文字列や__toStringメソッドが定義されているオブジェクトに関してはエスケープされるので、コントローラ側でshow_errorsの結果をViewに渡してもタグがエスケープされた状態になっています。そのため、View側で元の状態に戻す必要があります。

この、View内で使用される変数のエスケープ処理については、config.phpにあるsecurityセクションのoutput_filter, auto_filter_ouput, whitelisted_classesの設定値を参照しており、各値については以下のような意味合いになります。

  • output_filter: エスケープ処理の関数
  • auto_filter_ouput: 自動でエスケープするか
  • whitelisted_classes: エスケープ処理を適用しないクラス(Viewに渡した値が指定されたクラスのインスタンスだった場合にエスケープ処理は適用されない)

詳しくは、公式のSecurityクラスのドキュメントを参照してください。

Security – Classes – FuelPHP Documentation

エスケープせずにビューにデータを渡したい場合には、下記のようにViewオブジェクトのインスタンスに変数を直接設定することで可能です。

$view = View::forge('validation/index');
$view->set_safe('error_html', $validation->show_errors());

部分検証

場合によっては設定した項目全てではなく、一部の項目についてのみ検証したいということがあるかもしれません。そういった使い方をしたい場合には、下記のようにすることで部分的な検証が行えます。

// 第1引数は、検証対象の項目名と値の連想配列
// 第2引数は、部分検証を行うかどうか
if ($validation->run(array('username' => Input::post('username')), true)) {
    // 検証成功
} else {
    // 検証失敗
}

ただし、この場合は、送信された情報の中にemailが含まれていない場合のみです。データが送られてきていて、検証ルールも設定されているが、実際に検証したいのは一部のみ、という時には下記のように、第二引数に部分検証を行う項目を配列で指定します。

// 第1引数は、検証対象の項目名と値の連想配列
// 第2引数は、部分検証を行う項目
if ($validation->run(array('username' => Input::post('username')), array('username'))) {
    // 検証成功
} else {
    // 検証失敗
}

カスタムバリデーション

これまでは、デフォルトで提供されている検証ルールのみを使用してきました。ただ、業務で利用している場合、データベースの値と照合したりなど、足りない部分というのがあります。

そこで、app/classes/myvalidation.phpに下記のような独自のValidationクラスとStaticな検証用メソッドを定義します。検証用メソッドのプレフィックスは_validation_である必要があります。

class Myvalidation {
    public static function _validation_myvalid($val) {
        return $val == 'fukata';
    }
}

ファイル名については、下記のadd_callableで指定している値と一致していれば良いです。

これを先程の検証ルールで利用するには、下記のように変更します。カスタムバリデーション用のメッセージについても下の方に書いている「メッセージの変更」で書いているvalidation.phpに追記すれば大丈夫です。

// 2. 検証ルール設定
$validation->add_callable('myvalidation');
// 2.1. username項目の検証ルール設定
$validation->add('username', 'ユーザ名')
    ->add_rule('required')
    ->add_rule('mix_length', 4)
    ->add_rule('max_length', 10)
    ->add_rule('myvalid');

モデルとの連携

今回のサンプルでは、DBとやり取りする部分については書いていませんが、実際には、_validation_myvalidmodelの中で、DBに問い合わせなどを行ったりするコードを書きます。また、先ほど定義した、_validation_myvalidには無かった$optionという引数が追加されています。これは、min_lengthやmax_lengthのように引数を受け取る変数になっています。$option引数に関しては、先ほど定義した_validation_myvalidメソッドでも同じ様に第二引数にオプションを受け取れます。

今回の場合、入力されたメールアドレスが$optionに指定された値と一致しているかというのをチェックしています。さらに、Validation::active()を使い、その時検証中のFieldsetを取得し、エラーメッセージも設定するようにしています。

ファイル:app/classes/model/validation.php

class Model_Validation extends Model {
    public static function _validation_myvalidmodel($val, $option) {
        if ($option != $val) {
            // 独自でエラーメッセージを設定
            Validation::active()->set_message('myvalidmodel', ':label is hogehoge');
            return false;
        } else {
            return true;
        }   
    }   
}

これを先程の検証ルールで利用するには、下記のように変更します。

// 2.2. email項目の検証ルール設定
$validation->add_model('Model_Validation');
$validation->add_field('email', 'メールアドレス', 'required|min_length[10]|max_length[128]|myvalidmodel[fukata@example.com]');

エラー用タグのカスタマイズ

上記のValidationのドキュメントにも書かれていますが、fuel/app/config/config.phpに下記のようなセクションを追加することで、Fuel\Core\Validation#show_errorsメソッド時のHTMLを変更する事が出来ます。

/** 
 * Validation settings
 */
'validation' => array(
    'open_list' => '<ul>',
    'close_list' => '</ul>',
    'open_error' => '<li>',
    'close_error' => '</li>',
    'no_errors' => '', 
),

検証可能なHTTPメソッド

CodeIgniterのForm_ValidationはPOSTのみ対応していましたが、FuelPHPのValidationはGET, POST, PUT, DELETEの各メソッドに対応しています。

メッセージの変更

fuel/core/lang/en/validation.phpを参考に、fuel/app/lang/en/validation.phpにそれぞれのルールに対してのエラーメッセージを記載すれば変更できます。また、enではなく、fuel/app/lang/ja/validation.phpを作成することで、エラーメッセージの国際化にも対応する事が出来ます。デフォルトのメッセージを日本語にしたい場合は、config.phpにあるlanguageの項目をenからjaに変更するだけで大丈夫だと思います。

関連ファイル

今回、Validation周りを使用するに当たって、主に調べたファイル群です。

  • fuel/core/classes/validation.php
  • fuel/core/classes/fieldset.php
  • fuel/core/classes/security.php

まとめ

CodeIgniterのForm_Validationと似ている箇所がいくつかあるため、CodeIgniterを以前使用していた人に取ってはそれほど違和感なく使えるんじゃないでしょうか。

初のAdvent Calendar参加かつ、今回初めてまともに調べたFWだったのでやけに時間がかかってしまいました。また、抜けなどがあるかもしれません。もし、間違い等がありましたら指摘していただければ修正します。とりあえず、書き終えれて良かったです。

最後に、Advent Calendarですが、まだまだ参加者が少ないので、良かったら是非参加してみてください。

3日目:@NEKOGETさん ねこげっとぷれす » Model-View-ControllerそしてViewModel [FuelPHP]
5日目:@madmamorさん FuelPHPでFacebookアプリを作ってみよう。準備編。

関連記事