【PHP】CakePHPのvalidation機能の使い方

こんにちは!エンジニアのノムラです。

突然ですが、CakePHPのバリデーションの機能をみなさんはしっかり使いこなせていますか?

この記事では、

  • バリデーションでできること
  • バリデーションの使い方
  • バリデーションルール

といった、バリデーションについて基本的なことから、

  • エラー情報の取得
  • バリデーションが効かないときに確認したいこと

など、CakePHPのバリデーションについてわかりやすく解説していきたいと思います。

目次

CakePHPのvalidation

CakePHPのバリデーション機能は、入力された値が指定されたルールに沿っているかをチェックしてくれる機能です。

validationでできること

入力された値のチェックを行ってくれるバリデーションですが、どのようなルールに沿ってチェックするのでしょうか?

例えば、入力項目に空がないかチェックしてくれたり、日付の形式が指定した形式通りになっているかを確認することができます。

また、あらかじめ用意されているルールで判定できない場合は、独自のルールをつくることができます。

validationの使い方

バリデーションは対象のモデルに対して記述します。
基本的な書き方は以下のようになります。

$validator->ルール名('カラム名');

ルール名には、あらかじめCakePHPで用意されているルール名をいれ、カラム名はチェックを行いたいカラム名を指定します。

例えば、空かどうかをチェックする「notEmpty」を「name」というカラム名に適用しようとすると、

$validator->notEmpty('name');

というようになります。

第二引数にメッセージを指定すれば、エラーメッセージを任意のものに変更することが出来ます。
詳しいエラーメッセージの出力方法に関しては、後ほど解説します。

使える!validationのルール一覧

では、数字のみを許可する「numeric」を例にサンプルコードを見ていきましょう。

まずはバリデーションルール記述部分です。
usersTableのカラムに対してチェックを行うため、usersTable.phpに記述します。

【usersTable.php】

namespace App\Model\Table;
use Cake\Validation\Validator;
use Cake\ORM\Table;

class usersTable extends Table{

  public function validationDefault(Validator $validator){
    $validator->numeric('name');
    return $validator;

  }
}

コントローラーでは、データがPOSTされ、バリデーションエラーがなかった場合に登録されるよう処理を行います。

【TestController.php】

namespace App\Controller;
use Cake\Controller\Controller;
use Cake\ORM\TableRegistry;

class TestController extends AppController{

  public function index(){
    $this->loadModel('users');
    $entity = $this->users->newEntity($this->request->data);
    if($this->request->is('post')) {
      if(!$entity->errors()) {
        //エラーなし、登録処理
      }
    }
    $this->set(compact('entity'));
  }
}

バリデーションのエラーは、$entity->errors()に格納されていきます。

ビューはFormヘルパーを使って以下のように作成します。

【index.ctp】

<?= $this->Form->create() ?>
  <?= $this->Form->text('name') ?>
  <?= $this->Form->button('送信') ?>
<?= $this->Form->end() ?>

バリデーションチェックでエラーがなかった場合のみ登録され、エラーがあった場合は登録されません。

CakePHPで用意されているバリデーションルールとして、よく使うものをまとめてみました。

ルール機能
notEmpty未入力をチェックする
allowEmpty空を許可する
numeric数字のみかチェックする
alphanumeric文字と数字のみかチェックする
range指定した範囲内の値かチェックする
greaterThan指定値より大きいかチェックする
lessThan
指定値より小さいかチェックする
time
時間のフォーマットをチェックする
minLength
指定した最小文字数を満たしているかチェックする
maxLength
指定した最大文字数以内かチェックする
isUniqueユニークか調べる

これ以外にもたくさんのルールがあるので調べてみてください。

独自のルールを作る

CakePHPでは用意されているルール以外にも、独自のバリデーションルールをつくることもできます。

独自のルールはテーブルに直接書かず、src\Model\Validationというディレクトリを作成して記述します。
今回はそこにCustomValidation.phpというファイルを作成し、そこに独自のルールを作りました。

サンプルコードで具体的な例を見ていきましょう。

【CustomValidation.php】

namespace App\Model\Validation;
use Cake\Validation\Validation;

class CustomValidation extends Validation {
  //独自のルール
  public static function postal_codeCustom($check) {
    return (bool)  preg_match('/^([0-9]{3})(-[0-9]{4})?$/i', $check);
  }
}

サンプルでは、郵便番号を正規表現でチェックするカスタムバリデーションを作成します。

このとき、作成するfunctionは「static」にするという点に注意してください。
「static」にしないとエラーがでてしまいます。

テーブルは以下のようになります。

【usersTable.php】

namespace App\Model\Table;
use Cake\Validation\Validator;
use Cake\ORM\Table;

class usersTable extends Table{

  public function validationDefault(Validator $validator){
    //プロバイダ設定
    $validator->setProvider('Custom', 'App\Model\Validation\CustomValidation');
    $validator->notEmpty('postal_code')
              ->add('postal_code', '', [
                       'rule' => ['postal_codeCustom'],
                        'provider' => 'Custom',
                        'message' => '郵便番号の形式が違います。']);

    return $validator;

  }
}

カスタムバリデーションを使う場合、$validator->setProvider(キー、値)メソッドを利用する。プロバイダのキーとして‘Custom’、値はCustomValidationのファイルパスを示すよう‘App\Model\Validation\CustomValidation’のように設定し、addで作成したカスタムバリデーションを追加します。

providerには、プロバイダ設定のとき指定したプロバイダのキーを入れてください。

バリデーションでエラーがあった場合、指定したエラーメッセージが返ってきます。

validationのエラー情報を取得

バリデーションでエラーがあった場合、エラー内容を取得して処理を行いたい場合があると思います。
エラーメッセージの設定方法や、エラーログの出力について解説します。

任意エラーメッセージを設定する

CakePHPには、多くのバリデーションルールが用意されていることを解説しましたが、それらのルールに対して任意のエラーメッセージを設定していくことも可能です。

指定したエラーメッセージを出力させてみましょう。

【usersTable.php】

namespace App\Model\Table;
use Cake\Validation\Validator;
use Cake\ORM\Table;

class usersTable extends Table{

  public function validationDefault(Validator $validator){
    $validator->maxLength('name', 6,'6文字以内で設定してください。');
    return $validator;
  }
}

最大文字数をこえていないかチェックするmaxLengthでは、第一引数にカラム名、第二引数に最大文字数を指定します。

第三引数には、任意のエラーメッセージを指定してください。

ビューは以下のようになります。

【index.ctp】

<?= $this->Form->create($entity) ?>
  <?= $this->Form->text('name') ?>
  <?= $this->Form->error('name') ?>//error()でバリデーションエラーを出力
  <?= $this->Form->button('送信') ?>
<?= $this->Form->end() ?>

ビューでバリデーションエラーのerror()を使う場合は、create()の第一引数にエンティティを渡す必要があります。

error()で指定したエラーメッセージを出力しているため、画面には「6文字以内で設定してください。」と出力されます。

エラーログを出力する

エラーログを出力する場合は、バリデーションエラーがあったときにログを出力する処理を加えます。

【TestController.php】

class TestController extends AppController{

public function index(){
  $this->user = TableRegistry::get('users');
  $entity = $this->user->newEntity($this->request->data);

    if($this->request->is('post')) {
      if(!$entity->errors()) {
        //エラーなし、登録処理
      }else{
        //エラーログ出力
        $this->log('validationErrors=' . var_export($entity->errors(), true));
      }
    }
    $this->set(compact('entity'));
}

ログを出力するファイルを指定していない場合は、logs/error.logに出力されます。

上のサンプルコードだと、ログは以下のように出力されました。

2018-04-20 07:26:23 Error: validationErrors=array (
  'name' => 
  array (
    'maxLength' => '6文字以内で設定してください。',
  ),
)

バリデーションのエラーを出力していると、問題があったときに役に立ちます
ぜひ実践してみてください。

validationが正しく動作しないとき

正しく記述しているはずなのに、バリデーションが効かないエラーメッセージが出力されないというときがあるかと思います。

その場合以下のポイントをもう一度確認してみてください。

エラーメッセージが出力されない

エラーメッセージが出力されない場合、Viewファイルの$this->Form->create()に$entityが渡されているか確認しましょう。

任意のエラーメッセージを出力するときにも解説しましたが、エンティティをcreate()に渡していなければエラーメッセージは出力されません

エラー内容がViewファイルで使える状態になっているか確認してみましょう。

バリデーションが動作しないとき

バリデーションが動作しない場合は、コントローラー側でモデル名を間違えていないかを確認しましょう。

バリデーションでテーブル名を記述するとき、誤ったテーブルを指定していませんか?
当たり前ですが、指定するテーブルが変わるとバリデーションも効かなくなります。

簡単なミスですが、意外とよくあるのでもう一度確認してみてください。

バリデーションは、ルールの指定や引数などが多く慣れるまでは、簡単なミスでエラーがでてしまうということがあると思います。

自分の書いたコードをよく見直し、間違いはないかしっかり確認しましょう。

まとめ

CakePHPのバリデーションの使い方について、よく使うルールの解説や、エラーの出力方法などについて解説しました。

バリデーションの機能は、開発でも非常によく使う重要な機能です。
しっかりマスターしましょう!

この記事を書いた人

WEBエンジニアをやっています。
プログラミング初心者にもわかりやすく解説ができるよう頑張ります。

目次