よく使う独自バリデーションルールをプラグインのbehaviorにまとめる

CakePHP1.2.3を利用しています。

今までは「独自のバリデーション関数を追加(日本語の文字数チェック)」で書いたように、独自バリデーションルールをapp_modelとかに書いてモデルで使いまわしてたんですが、そろそろ汎用的なものはプラグインでまとめて複数プロジェクトで統一して使えるようにしたいと思い移行しました。


プラグインのbehaviorに独自バリデーションルールをまとめて、モデルから利用するまでのTipsです。

まずは、プラグインに関してはSlywalkerさんのCakePHP勉強会@tokyo #4の発表資料に目を通しておくと理解が早くなります。
http://d.hatena.ne.jp/slywalker/20090523/1243059244


プラグインの場所は、app/plugins以下が基本ですが、複数プロジェクトで使いまわすので任意のディレクトリにした方が楽です。その方法は下記に書いてあります。
http://d.hatena.ne.jp/cakephper/20090303/1236069340
本エントリにおいて、任意のプラグインディレクトリにする方法は必須ではありません。面倒な人はapp/plugins以下に置いておけばOK.


さて、これからが移植の手順です。まずはプラグインディレクトリとBehaviorファイルを下記の構成で作ります。今回はcakeplusプラグインという名前で作りました。

plugins/cakeplus/models/behaviors/add_validation_rule.php


このbehaviorを呼び出す場合は、通常のモデルファイル(例えばapp/models/post.php)の中で

<?
class Post extends AppModel {

	var $name = 'Post';
	var $actsAs = array('Cakeplus.AddValidationRule');

  	var $validate = array(
 		'hoge' => array(
			"rule1" => array('rule' => array('maxLengthJP', 5),
 				'message' => 'hogeは5文字以内です'
 			),
 		),
 	);
}
?>

として、actsAsに配列で プラグイン名.ファイル名 という規則で記載すれば、add_validation_rule.phpの中のメソッドが利用できるようになります。
そして、add_validation_rule.php内の独自バリデーションルール(ここではmaxLengthJP)を通常の独自バリデーションルールと同じように記述すれば使えます。



plugins/cakeplus/models/behaviors/add_validation_rule.phpの中は独自バリデーションルールを記載します。今回は日本語の文字数の上限チェックのルールを記載しています。

<?php
class AddValidationRuleBehavior extends ModelBehavior {
	/**
	 * マルチバイト用バリデーション 文字数上限チェック
	 */
	function maxLengthJP( &$model, $wordvalue, $length ) {
		$word = array_shift($wordvalue);
		return( mb_strlen( $word ) <= $length );
	}
}
?>

ここが注意点なのですが、pluginのbehaviorになるとmaxLengthJPメソッドの第一引数に渡される値が、通常のモデルやapp_model.phpで記述した場合と異なることです。第一引数には、モデル(コントローラ??)のオブジェクトが入ります。第2引数からPostされた項目の値が連想配列で入り、第3引数に上限値(ここではモデルから渡される数値の5)が入ります。

基本はこれだけです。


Postされたフィールドを利用したい場合、例えばemailの入力確認フィールドの内容が同じかどうかチェックする場合、

<?
class AddValidationRuleBehavior extends ModelBehavior {

	function checkCompare( &$model, $wordvalue , $suffix  ){

		$fieldname = key($wordvalue);

		return ( $model->data[$model->alias][$fieldname] === $model->data[$model->alias][ $fieldname . $suffix ] );


	}

}
?>

このように、第一引数で渡されたオブジェクトの中のdataの中に、モデル名.フィールド名の配列で値が入っているので、それを利用して比較します。



とりあえず今の段階で作ったbehaviorは下記になります。

plugins/cakeplus/models/behaviors/add_validation_rule.php

<?php

/**
 * 独自のバリデーションルールを追加するbehavior プラグイン
 * 内部文字コードはUTF-8(バリデーションで渡す文字データはUTF-8となります)
 *
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright 2009, Yasushi Ichikawa. (http://d.hatena.ne.jp/cakephper/)
 * @link          http://d.hatena.ne.jp/cakephper/
 * @package       cakeplus
 * @subpackage    cakeplus
 * @version       0.01
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 *
 *
 * =====利用方法=====
 * 各モデルファイルで、下記のように使う。app_modelにactsAsで指定しても可
 *	var $actsAs = array('Cakeplus.AddValidationRule');
 *
 * 各モデルファイル内のバリデーションの書き方は下記を参考に。
 * 	var $validate = array(
 * 		'test' => array(
 *			"rule2" => array('rule' => array('maxLengthJP', 5),
 * 				'message' => '5文字以内です'
 * 			),
 *			"rule3" => array('rule' => array('minLengthJP', 2),
 * 				'message' => '2文字以上です'
 * 			),
 *			"rule4" => array('rule' => array('checkCompare', '_conf'),
 * 				'message' => '値が違います'
 * 			),
 * 			"rule5" => array('rule' => array('space_only'),
 * 				'message' => 'スペース以外も入力してください'
 * 			),
 * 			"rule6" => array('rule' => array('katakana_only'),
 *				'message' => 'カタカナのみ入力してください'
 * 			),
 * 		),
 * 	);
 *
 *
 */
class AddValidationRuleBehavior extends ModelBehavior {

    function setup(&$model, $config = array())
    {
        //$this->settings = $config;
        mb_internal_encoding("UTF-8");
    }


	/**
	 * マルチバイト用バリデーション 文字数上限チェック
	 *
	 * @param array &$model
	 * @param array $wordvalue
	 * @param int $length
	 * @return boolean
	 */
	function maxLengthJP( &$model, $wordvalue, $length ) {
		$word = array_shift($wordvalue);
		//return( mb_strlen( $word, mb_detect_encoding( $word ) ) <= $length );
		return( mb_strlen( $word ) <= $length );
	}

	/**
	 * マルチバイト用バリデーション 文字数下限チェック
	 *
	 * @param array &$model
	 * @param array $wordvalue
	 * @param int $length
	 * @return boolean
	 */
	function minLengthJP( &$model, $wordvalue, $length ) {
		$word = array_shift($wordvalue);
		return( mb_strlen( $word ) >= $length );
	}


	/**
	 * フィールド値の比較
	 * emailとemail_confフィールドを比較する場合などに利用
	 * _confは$suffixによって変更可能
	 *
	 * @param array &$model
	 * @param array $wordvalue
	 * @param string $suffix
	 * @return boolean
	 */
	function checkCompare( &$model, $wordvalue , $suffix  ){

		$fieldname = key($wordvalue);

		return ( $model->data[$model->alias][$fieldname] === $model->data[$model->alias][ $fieldname . $suffix ] );


	}



	/**
	 * 全角カタカナ以外が含まれていればエラーとするバリデーションチェック
	 *
	 *
	 * @param array &$model
	 * @param array $wordvalue
	 * @return boolean
	 */
	function katakana_only( &$model, $wordvalue){

	    $value = array_shift($wordvalue);

	    return preg_match("/^[ァ-ヶー゛゜]*$/u", $value);

	}




	/**
	 * 全角、半角スペースのみであればエラーとするバリデーションチェック
	 *
	 * @param array &$model
	 * @param array $wordvalue
	 * @return boolean
	 */
	function space_only( &$model, $wordvalue){

	    $value = array_shift($wordvalue);

	    if( mb_ereg_match("^(\s| )+$", $value) ){

		    return false;
	    }else{
	        return true;
	    }
	}


	/**
	 * only Allow 0-9, a-z , A-Z
	 *
	 * @param array ref &$model
	 * @param array $wordvalue
	 * @return boolean
	 */
	function alpha_number( &$model, $wordvalue ){
		$value = array_shift($wordvalue);
		return preg_match( "/^[a-zA-Z0-9]*$/", $value );

	}

}

?>


今後は下記URLのgit hubで更新していく予定です。
http://github.com/ichikaway/cakeplus/tree/master



追記(2009/7/6)
掲載していたソースコードが古くなったため、最新版(github版)に修正しました。