スポンサーリンク

CodeIgniter – フォームバリデーションの優先順位を知る

CodeIgniterを始めて一番最初に躓いたのがフォームバリデーションについてです。

バリデーションの種類として標準で定義されているものに加えて、コールバック(callback)関数を用いてオリジナルなバリデーションを定義することも出来ます。

 

私は、とある入力欄が入力されているか、かつデータベースに存在するか(validate_credentialsという自分で定義した関数でチェック)という検証をしたかったので、

$this->form_validation->set_rules("hoge", "HOGE", "required|trim|callback_validate_credentials");

と書きました。

入力チェックはrequiredで検証します。とあるCodeigniter入門サイトのコードを真似て書いたものですが、未入力の時は必須エラーとなり、データベースに存在しない場合は独自のエラーメッセージを表示することを想定しています。しかしながら、未入力で送信して検証すると先にvalidate_credentials関数でのチェックが行われてしまいます。

この原因と対策について調べると、

  • callbackが優先されるのがは通常の仕様である
  • ルールを分けてrequired→callbackの順に検証するような処理にする
  • コアの_prepare_rulesをcallbackよりもrequiredが優先する処理でオーバライド

という事が分かりました。

2の場合はコードが長くなってしまうので3の方法を採用します。

下記コードは、公式フォーラムのスレッドにかつて掲載されていたものです。

<?php
class  MY_Form_validation extends CI_Form_validation {
  public function __construct()
  {
    parent::__construct();
  }

  protected function _prepare_rules($rules)
  {
    // Required rules always go first
    $required_rules = array();
    $new_rules = array();
    $callbacks = array();

    foreach ($rules as &$rule)
    {
      // Let 'required' always be the first rule
      // No use in running any callbacks if required has not been checked
      if ($rule === 'required')
      {
          array_unshift($required_rules, 'required');
      }
      // 'isset' is a kind of a weird alias for 'required' ...
      elseif ($rule === 'isset' && (empty($new_rules) OR $new_rules[0] !== 'required'))
      {
          array_unshift($required_rules, 'isset');
      }
      // The old/classic 'callback_'-prefixed rules
      elseif (is_string($rule) && strncmp('callback_', $rule, 9) === 0)
      {
          $callbacks[] = $rule;
      }
      // Proper callables
      elseif (is_callable($rule))
      {
          $callbacks[] = $rule;
      }
      // "Named" callables; i.e. array('name' => $callable)
      elseif (is_array($rule) && isset($rule[0], $rule[1]) && is_callable($rule[1]))
      {
          $callbacks[] = $rule;
      }
      // Everything else goes at the end of the queue
      else
      {
          $new_rules[] = $rule;
      }
    }

    // Required rules go first, then any callbacks, then the rest
    $callbacks = array_merge($required_rules, $callbacks);
    return array_merge($callbacks, $new_rules);
  }
}

上記コードを、プレフィックスのMY_を付けた”MY_Form_validation.php”として”application/libraries”に保存します。

これで期待する動作になりました。

タイトルとURLをコピーしました