読者です 読者をやめる 読者になる 読者になる

カスタムバリデーションルール

cakephp
  • モデル名:Employee
  • コントローラ名:Validations(紛らわしいなあ、と後で思う)
    • 上記で使用するモデルを$usesでEmployeeに設定

モデル

APP/model/employee.php
  • カスタムバリデーションルール:$validate_edit
  • 一つのフィールドに対し複数のルールを設定
    • 最初にエラーになったルールでバリデーションを停止するため"last"=>true設定
  • カスタムバリデーションメソッドcheckNameを定義。複雑なバリデーションに対応。
<?php
class Employee extends AppModel{
	var $name = 'Employee';
	var $recursive = 3;	//関連するレコードも最大限取得

	var $validate = array(
    /* 複数のカスタムバリデーションルールを設定しないときはここに書く */
	);

	//バリデーションルール:編集、追加
	var $validate_edit = array(
		'name' => array(
			array("rule"=>VALID_NOT_EMPTY,		"message"=>"名前が空白です",	"last"=>true,),
			array("rule"=>array("checkName"),	"message"=>"登録済みです",		"last"=>true,	"on"=>array("create")),
		),
		'past_score' => array(
			array("rule"=>VALID_NOT_EMPTY,	"message"=>"過去の得点が空白です",		"last"=>true,),
			array("rule"=>VALID_NUMBER,		"message"=>"数値を入力してください",	"last"=>true,),
		),
	);

	function checkName(){
		if(!$this->isUnique($this->data["Employee"]["name"])){
			return false;
		}
		return true;
	}
}
?>
APP/app_model.php
  • beforeValidate:validate関数がコールされると自動的に呼ばれるコールバック関数
    • 冒頭でオリジナルのバリデーションルールを保存する。
    • validate実行前に呼び出し元で、validationSetにカスタムバリデーション名をセットする。カスタムバリデーションルールセットはモデルで定義。モデルでvalidate_editで定義したなら「edit」を設定(コントローラ参照)。
  • afterValidate:カスタムバリデーションルールの後始末関数(独自)
    • 保存しておいたオリジナルのバリデーションルールを再設定。
  • validate:親クラスのvalidate関数をオーバーライドしたもの。
    • 冒頭で親クラスのvalidate関数を呼ぶ
    • 最後にafterValidateを呼んで後始末
<?php
class AppModel extends Model{
	//コールバック関数
	function beforeValidate(){
		debug("AppModel::beforeValidate called");	//for Debug
		$this->validateOrg = $this->validate;	//オリジナルのバリデーションルールの保存
		if ($this->validationSet){
			$param = 'validate_' . $this->validationSet;	//カスタムruleの決定
			$this->validate = $this->{$param};	//カスタムruleの読み込み
		}
		return true;
	}

	//非コールバック関数
	function afterValidate(){
		debug("AppModel::afterValidate called");	//for Debug
		$this->validate = $this->validateOrg;	//オリジナルのバリデーションルールの再設定
		return true;
	}

	//バリデーション
	function validates(){
		debug("AppModel::validates called");	//for Debug
		$errors = parent::validates();	//親クラスのvalidate関数を呼ぶ(フラグをセット)
		//後始末
		$this->afterValidate();	//AppModel::afterValidate
		return $errors;
	}
}

コントローラ

APP/controllers/validations_controller.php
  • バリデーション実行後はモデルのデータを呼び出すような関数を実行しない(read等)。エラーフラグがリセットされる(これで二日悩む)。
<?php
class ValidationsController extends AppController {
	var $name = 'Validations';
	var $uses = array('Employee');

	//index
	function index($id=null){
		$this->pageTitle = "データバリデーションの例";
		$this->Employee->id = $id;

		debug("ValidationsController::index called");	//for Debug
		if($this->data){
			//フォームよりデータを受信
			$this->Employee->validationSet = 'edit';	//カスタムルールセット名を設定
			$rtn =  $this->Employee->set(array("Employee"=>$this->data["Validation"]));	//データをセット
			//save():引数無しだと自動的にデータバリデーションが実行される
			if($this->Employee->save()){
				//データ保存時にvalidates実行:OK
				$this->flash('編集されたデータを保存しました', '/menu');
			}	//NG:もとの画面
			$this->set('employee', array("Employee"=>$this->data["Validation"]));
		}else{
			//初期表示
			//validationした後にEmployeeモデルのデータを取得するとEmployeeモデルのvalidation flagがクリアされてしまうので注意
			$this->set('employee', $this->Employee->read());
		}

	}	//index

}	//ValidationsController
?>

ビュー

APP/views/validations/index.ctp
    • Form::error(モデル名.フィールド名)であら便利。
<?php echo $form->create('Validation', array('method'=>'post', 'action'=>"/index/{$employee['Employee']['id']}/")); ?>
<table>
	<tr><th>氏名</th><td>
	<?php
		echo $form->text('name', array('value'=>$employee['Employee']['name']));
		echo $form->error('Employee.name');
	?>
	</td></tr>
	<tr><th>過去の持点</th><td>
	<?php
		echo $form->text('past_score', array('value'=>$employee['Employee']['past_score']));
		echo $form->error('Employee.past_score');
	?>
	</td></tr>
</table>
<?php echo $form->hidden('id', array("value"=>$employee['Employee']['id'])); ?>
<?php echo $form->end('変更'); ?>

エラーフラグがリセットされる原因に気づかなくて大変疲れました・・・。