バリデーション
リクエストの検証
入力フォームなどによってユーザーの入力をPOSTやGETなどの形式で受け付けるアプリケーションの場合、想定外の入力はエラー扱いとして入力を受け付けないようにする必要があります。
Validatorクラスを利用するとこの仕組が容易に実装可能です。
Validatorクラスの利用
例えばユーザー情報の入力フォームを想定します。
<form method="post"> 名前:<input type="text" name="name" /><br /> 住所:<input type="text" name="address" /><br /> 年齢:<input type="text" name="age" /><br /> <input type="submit" value="送信"> </form>
名前、住所、年齢を入力するだけの簡単なフォームです。
全ての項目は必須入力とします。
そして名前は30文字以内、年齢は数字のみというルールにしようとします。
Validatorクラスでこれらのルールに従って検証を行います。
まず検証ルールを設定する必要があります。検証ルールの設定はsetRulesメソッドを利用し、配列で指定します。
$rules = array(
'name' => array(
array('rule' => 'required'),
array('rule' => 'length', 'max' => 30)
),
'address' => array(
array('rule' => 'required')
),
'age' => array(
array('rule' => 'required'),
array('rule' => 'number_string')
)
)
$validator = new Validator();
$validator->setRules($rules);
項目名をキーとする配列とし、各キーの下には複数の検証ルールを配列で指定します。
更に各ルールは検証条件を配列で指定します。
このように全ての検証条件を階層的な配列として設定します。
設定したうえでvalidateメソッドによって検証を実行します。
$result = $validator->validate($this->post); if ($result == false) { $errors = $validator->getError(); }
validateメソッドを実行するとsetRulesで設定したルールにもとづいて検証が行われ、一つでもエラーが存在する場合はvalidateはfalseを返します。
この場合、getErrorによって項目ごとのエラーメッセージが取得できます。このエラーメッセージを入力フォームに表示することにより、ユーザーに訂正を促します。
検証ルールの種類
検証ルールは以下の物が用意されています。
| ルールキー | 検証内容 | オプション |
|---|---|---|
| required | 必須入力 | |
| length | 文字列長範囲 | max、min |
| length_range | lengthのエイリアスです。lengthと同一動作です。 ※このルールは削除予定のため、lengthで代用するようにしてください。 | max、min |
| numeric | 算術数値 | |
| number_string | 数字文字列(0~9) | |
| alpha | アルファベット | |
| alphanum | アルファベット・数字文字列 | |
| singlebyte | シングルバイト | |
| regex | 正規表現 | pattern |
ユーザー定義ルール
Validatorの内部では、ルールキーをキャメルケースに変換したメソッド名が呼び出され、ルールキーごとの検証処理を行なっています。
例えばlength_rangeの場合、ValidatorのlengthRangeメソッドによって実際の検証が行われています。
ユーザーが任意の検証ルールを追加したいと考えた場合、Validatorを継承したクラスを定義し、そこにユーザー定義メソッドを追加すれば、そのメソッド名をスネークケースに変換した名前のルールキーを指定することにより、validateメソッドで利用可能になります。
例えば郵便番号を検証するzipCodeというメソッドをValidatorの継承クラスに定義します。
class ValidatorEx extends Validator { public function __construct() { self::$_messages['zip_code'] = 'invalid zip code'; } public function zipCode($value, $options) { if (!preg_match('/^[0-9]{3}-[0-9]{4}$/', $value)) { return false; } return true; } }
この場合、setRulesメソッドに設定するルールで、ルールキーとして"zip_code"を指定することで、zipCodeメソッドを利用しての検証が行われます。
ただし、ユーザー定義メソッドは必ず引数を2つとり、第1引数に検証対象値、第2引数に検証オプションとする必要があります。第2引数は引数としての定義は必要ですが、不要な場合はメソッド内部では利用する必要はありません。
$validator->setRules(array(
'zip' => array(
array('rule' => 'required'),
array('rule' => 'zip_code')
)
));
$post = array('zip' => '000-000');
$res = $validator->validate($post);
if ($res == false) {
// array('zip' => 'invalid zip code')
$errors = $validator->getError();
}
コントローラーに組み込まれたValidatorを利用する
ControllerはフィールドとしてValidatorのインスタンスを保持しています。
これを利用しての検証が可能です。
setRulesメソッドによるルールの設定は自動的に行われます。
ただしコントローラークラスの$validateRulesフィールドにルールを定義しておく必要があります。
$validateRulesは、setRulesメソッドに指定する配列を、更にアクション名をキーとした配列の下に格納します。
class UserController extends Controller { protected $validateRules = array( 'regist' => array( 'name' => array( array('rule' => 'required'), array('rule' => 'length', 'max' => 30) ), 'address' => array( array('rule' => 'required') ), 'age' => array( array('rule' => 'required'), array('rule' => 'number_string') ) ) ); public function index() { } public function regist() { // $this->validateRules['regist']のルールで検証が行われる $res = $this->validator->validate($this->post); if ($res == false) { $this->session->errors = $this->validator->getError(); $this->redirect('/user/index'); } } }
アクションメソッドではvalidateメソッドを呼び出すだけです。
ユーザー定義のValidator継承クラス
Validatorクラスを継承したクラスをコントローラーの$this->validatorとして利用したい場合、index.phpで以下の2行の設定が必要です。
例えばlibraryディレクトリにValidatorExクラスを定義した場合は以下のようにします。
・ ・ ・ @@Brequire_once SITE_PATH . 'library/validator_ex.php';@ $dispatcher = new Dispatcher(); @@B$dispatcher->setValidatorClass('ValidatorEx');@ ・ ・ ・
オートバリデート
コントローラーにはバリデーションを自動的に行う機能が備わっています。
通常はValidatorクラスのvalidateメソッドにより、アクションメソッドの中で明示的にバリデーションを行いますが、Controllerクラスの$autoValidateをtrueに設定すると、それすらも必要なく、アクションメソッドより前のタイミングで自動的に検証が行われ、エラーがある時にはリクエスト送信元のアクションへリダイレクトし、エラーを表示します。
class UserController extends Controller { protected $autoValidate = true; protected $validateRules = array( 'regist' => array( 'name' => array( array('rule' => 'required'), array('rule' => 'length', 'max' => 30) ), 'address' => array( array('rule' => 'required') ), 'age' => array( array('rule' => 'required'), array('rule' => 'number_string') ) ) );
Controllerを継承したクラスで$autoValidateフィールドをtrueに指定した上で、
$validateRulesを設定すると、設定されたアクションへのリクエスト時、自動的に検証が実行されます。
検証の結果、エラーが存在しない場合はアクションまで処理が到達します。
エラーが存在した場合、リクエスト元のアクションへリダイレクトします。
このリダイレクト時、リダイレクト先(リクエスト元)のアクションでは、ビューへ"errors"というキーでエラー情報が出力されます。
errorsは、エラー対象となったPOSTやGETの項目のキーにエラーメッセージが格納された配列となっており、ビューテンプレートでこれを表示するようにすることで、エラーが表示が可能です。
class UserController extends Controller { protected $autoValidate = true; protected $validateRules = array( 'regist' => array( 'name' => array( array('rule' => 'required'), array('rule' => 'length', 'max' => 30) ), 'address' => array( array('rule' => 'required') ), 'age' => array( array('rule' => 'required'), array('rule' => 'number_string') ) ) ); public function index() { } public function regist() { // 登録処理 } }
<form method="post" action="/user/regist"> 名前:<input type="text" name="name" /><span class="error"><?php echo $errors['name'] ?></span><br /> 住所:<input type="text" name="address" /><span class="error"><?php echo $errors['address'] ?></span><br /> 年齢:<input type="text" name="age" /><span class="error"><?php echo $errors['age'] ?></span><br /> <input type="submit" value="送信"> </form>
例えば上の例のようなコントローラークラスとビューテンプレートを用意すれば、これだけで検証が自動的に行われ、エラー表示までが行われます。
こうすることでアクションメソッド内にはバリデーションコードを一切記述せずにバリデーション機能を持たせることが可能になり、コードがシンプルになります。