CakePHP2を使用して複数フィールドにわたるバリデーションを行う

単一のフィールドでバリデーションを行うには、モデルでバリデーションを定義してやればいいのですが、複数のフィールドにかかるバリデーションはどうすればいいのかわかりませんでした。 今回取り扱う、複数のフィールドにまたがるバリデーションというのは以下のような電話番号のフィールドや名前のフィールドなどです。

1つずつフィールドにバリデーションするとエラーメッセージがいくつも出てくる

結論からいうと、

自分で関数を定義する

ことによって解決しました。 例えば、空のフィールドを許さないバリデーションを行う場合は以下のようにモデルに書くと思います。

モデル

<?php
class Posts extends AppModel {
   public $validate = array(
      'test_field' => array(
         'rule' => array('notEmpty'),
         'message' => '文字を入力してください。'
      )
   );
}

ここでruleに指定してあるnotEmptyというものは、CakePHP側で作成してある組み込み関数になります。
ちなみにnotEmptyがどこに定義してあるかは公式ドキュメントに書いてあります。

notEmpty – CakePHP公式ドキュメント

ruleに指定している部分が関数なのであれば、自分で作成しよう! ということで複数フィールドにわたるバリデーションも自作の関数を作成することで解決出来ます。
それではさきほどの画像のような、電話番号のバリデーションを行なってみましょう。

Viewに以下のように書いてあるとします。

<?php echo $this->Form->create('Post');?>
<?php echo $this->Form->text('tel1', array('label' => false));?> - 
<?php echo $this->Form->text('tel2', array('label' => false));?> - 
<?php echo $this->Form->text('tel3', array('label' => false));?>
<?php echo $this->Form->end('送信');?>

この場合、tel1,tel2,tel3それぞれにバリデーションをしてもよいのですが、tel1,tel2が空のフィールドだったりした場合、エラーメッセージが2つ表示されることになります。

モデルに全てのフィールドが空のフィールドを許さず、数字のみしか受けつけないという関数を作成し、$validateに定義します。

<?php
class Post extends AppModel {
   public $validate = array(
      'tel1' => array(
         'notEmpty' => array(
            'rule' => 'checkNotEmpty', //下に関数を定義している
            'message' => '電話番号を入力してください。'
         ),
         'custom' => array(
            'rule' => 'checkNumberAll', //下に関数を定義している
            'message' => '数字のみ入力してください。'
         )
      )
   );

   public function checkNotEmpty(){
      if(!empty($this->data['Post']['tel1']) && 
         !empty($this->data['Post']['tel2']) && 
         !empty($this->data['Post']['tel3'])) {
            return true;
      } else {
            return false;
      }
   }

   public function checkNumberAll(){
      // 数字のみ許可
      $pattern = '/^[0-9]+$/';
      $tel1 = preg_match($pattern, $this->data['Post']['tel1']);
      $tel2 = preg_match($pattern, $this->data['Post']['tel2']);
      $tel3 = preg_match($pattern, $this->data['Post']['tel3']);
      if(empty($tel1) && empty($tel2) && empty($tel3)){
         return true;
      } else {
         return false;
      }
   }
}

これで複数フィールドのバリデーションをすることが出来、エラーメッセージも1つしかはかなくなります。
$this->dataで無理やり行なっている部分を汎用性のあるものにするのが次のステップですね。
もっとよいやり方があれば教えていただきたいです。

この記事は以下のページを参考にしました。
CakePHP Users in Japanのほうのページには、汎用性のある関数が書かれているのでそれを見ながら上の関数たちを汎用性のあるものに変えていこうと思います。

参考ページ

“複数のフィールドにまたがるバリデーションは?” フォーラム – CakePHP Users in Japan

notEmpty – CakePHP公式ドキュメント

追記(2012年9月13日15:30)
公式ドキュメントにもしっかり書いてありました。。
こういうのって気づいたあとに見えるようになりますよね。。
Model – CakePHP API(validateの部分)