バリデートをXMLで行う

※ソースは最下部

ZendFrameworkでのバリデーションは普通Zend_Validateを使います。
といっても、分離されているので単独のパッケージですが。

Zend_Validate

通常では

<?php
// バリデータチェインを作成し、そこにバリデータを追加します
$validatorChain = new Zend_Validate();
$validatorChain->addValidator(new Zend_Validate_StringLength(6, 12))
               ->addValidator(new Zend_Validate_Alnum());
?>

のように記述していくのですがさすがに毎回それぞれのエラーメッセージを設定したりとめんどくさいです。
なにより送られてくる一つ一つの項目に上記のようなチェックを書くのは正直めんどいです
そこでXMLでZend_Validateを使えるようにしたので紹介。
といっても最低限動くようにチャチャっと作って、後で細かい部分とかコードは調整しようと思っていたので、汚いですが・・・

具体例のほうが分かりやすいと思うので
例として

  • hoge_id」というキーで値が送られてくる
  • hoge_id」は整数で1000以下
<?xml version="1.0" encoding="UTF-8"?>
<validate>
	<!-- hoge_id -->
	<!--   notmust="true"を指定すると空文字列かnullの場合にはバリデートをスキップ -->
	<hoge_id  notmust="true">
		<!--
		バリデータごとに個別にインバリッドのときのメッセージを指定しないで
		キーごとにまとめて基本のメッセージを指定することもできます
		-->
		<default_invalid_msg></default_invalid_msg>
		<validate>
			<!--
			break="true"だった場合そのキーの値の中のバリデートのリストで
			インバリッドだった場合に次以降のバリデートをスキップします
			※この場合したのZend_Validate_LessThanのチェック項目
			-->
			<rule break="true">
				<!--
				バリデートに使うクラス
				Zend_Validate_Interfaceを実装したクラス
				-->
				<validate_class>Zend_Validate_Digits</validate_class>
				<!-- インバリッドの時のメッセージ -->
				<invalid_msg>整数で入力してください</invalid_msg>
			</rule>
			<rule break="true">
				<validate_class>Zend_Validate_LessThan</validate_class>
				<invalid_msg>1000以下の値を入力してください</invalid_msg>
				<!--
				引数は最大で3つまで有効
				引数は,で区切る
				必要になったら無限個数対応するけど・・・めんどいからやめました
				-->
				<args>1000</args>
			</rule>
		</validate>
	</hoge_id>
</validate>
<?php
Zend::loadClass('Toytools_ValidateByXml');
$validator = new Toytools_ValidateByXml( dirname(__FILE__).DIRECTORY_SEPARATOR.'ValidateTest.xml' );
$validator->valid( $_POST );
//$validator->valid( $this->_getAllParams() );//ZendFrameworkの場合はこんな感じ
if( !$validator->isValidAll() ){
	//全てOK
}else{
	if( !$validator->isValid('hoge_id') ){
		$invalidMsg = $validator->getInvalidMessageList('hoge_id');
		//....とか色々
	}
}
?>

みたいな感じで書けます

  • 送られてきたキーが増える場合にはと同階層にキーをタグ名にしたものを増やしていけばOK
  • デフォルトで用意されているバリデートクラスは十分とはいえないので必要になったらZend_Validate_Interfaceを実装したバリデートクラスを作る
  • 個別のインバリッドメッセージがなかったらデフォルトのインバリッドのメッセージを使うとか

まぁある程度の機能は用意されています
XMLのバリデートははいってません

以下ソース

Toytools_Debugつかってるので必要に応じてはずしてください
Toytools_Debugはこちらid:toytools:20070407

<?php
/**
 * @category   Toytools
 * @package    Toytools
 * @copyright  Copyright (c)kaw
 * @license    
 * @version    
 */

class Toytools_ValidateByXml{
	//VALID TYPE KEYS
	
	//
	private $_log;//Toytools_Debug
	private $_xmlPath;
	private $_invalidKeyList;//array
	private $_isValidAll;
	
	/*
	 * CONSTRUCT
	 * @param	XMLファイルのパス
	 */
	function __construct( $xmlPath ){
		$this->_log = new Toytools_Debug( __CLASS__ );
		$this->_xmlPath = $xmlPath;
		$this->_invalidKeyList = array();
		$this->_isValidAll = true;
	}
	
	
	/**
	 * XMLを読み込みバリデートを実行します
	 * @param	array
	 * @usage
	 * 			$validator->valid( $this->_getAllParams() );
	 */
	function valid(array $requestList){
		if( is_null( $this->_xmlPath ) ){
			throw new Exception("XmlPath can't find");
		}
		
		$xml = simplexml_load_file($this->_xmlPath);
		
		foreach( $xml as $validReqItem ){//
			$requestKey   = $validReqItem->getName();
			$requestValue = trim($requestList[$requestKey]);
			
			
			$this->_invalidKeyList[$requestKey] = array();
			
			$this->_invalidKeyList[$requestKey]['is_valid'] = true;
			$this->_invalidKeyList[$requestKey]['invalid_message_list'] = array();
			$this->_invalidKeyList[$requestKey]['invalid_class'] = array();
			
			$defaultValidMsg = (string)$validReqItem->default_invalid_msg;
			$this->_invalidKeyList[$requestKey]['default_invalid_message'] = ( trim($defaultValidMsg) == '' )? null : $defaultValidMsg ;
			
			
			//アトリビュートを展開します
			$requestKeyAttributes = array();
			foreach($validReqItem->attributes() as $a => $b) {
				$requestKeyAttributes[$a] = $b;
			}
			//必須でない宣言のチェック
			if( strtolower($requestKeyAttributes['notmust']) == 'true' && ( is_null($requestValue) || $requestValue == '' ) ){
				continue;
			}
			//
			foreach( $validReqItem->validate->rule as $validItem ){
				$validate_class  = (string)$validItem->validate_class;
				$invalid_msg     = (string)$validItem->invalid_msg;
				$args            = trim((string)$validItem->args);
				
				//アトリビュートを展開します
				$attributes = array();
				foreach($validItem->attributes() as $a => $b) {
					$attributes[$a] = $b;
				}
				Zend::loadClass( $validate_class );
				if( $args == '' ){
					$valid = new $validate_class();//None
				}else{
					//コンストラクタはcall_user_func_arrayで呼べないのでとりあえず並べとく
					$args_list = explode( ',' , $args );
					switch( count($args_list) ){
						case 1:
							$valid = new $validate_class( $args_list[0] );
							break;
						case 2:
							$valid = new $validate_class( $args_list[0] , $args_list[1] );
							break;
						case 3:
							$valid = new $validate_class( $args_list[0] , $args_list[1] , $args_list[2] );
							break;
						default:
							throw new Exception('ValidateXml ArgsLen is too long');
					}
				}
				//VALIDATE
				if( !$valid->isValid( $requestValue ) ){
					$this->_log->warn('INVALID  CLASS : '.$validate_class , $requestKey);
					$this->_isValidAll = false;
					$this->_invalidKeyList[$requestKey]['is_valid'] = false;
					$this->_addInvalidMessage( $requestKey , $invalid_msg , $validate_class );
					if( strtolower($attributes['break']) == 'true' ){
						break;
					}
				}
			}
		}
	}
	
	/**
	 * 全ての項目がValidかどうか
	 * @return boolean
	 */
	public function isValidAll(){
		return $this->_isValidAll;
	}
	
	
	/**
	 * 特定キーのものがValidかどうか
	 * @param	mixed バリデータのキー
	 * @return	boolean
	 */
	public function isValid( $requestKey ){
		if( is_null($this->_invalidKeyList[$requestKey]['is_valid']) ){
			return true;//nullの場合にはバリデートルールのXMLに制約が無いものと見なしTRUEを返却
		}
		return $this->_invalidKeyList[$requestKey]['is_valid'];
	}
	
	/**
	 * バリデータに失敗した箇所のメッセージのリストを取得する
	 * @param	mixed	バリデータのキー
	 * @param 	boolean	[OPTION]invalidでメッセージが無かった場合にデフォルトメッセージを返却するか
	 * @return	null | array
	 * @description
	 * 			返却がnullであってもvalidであったとは限りません
	 * 			validかの判定はisValidを使用してください
	 */
	public function getInvalidMessageList( $requestKey , $emptyUseDefault = true ){
		$invalidMessageList = $this->_invalidKeyList[$requestKey]['invalid_message_list'];
		if( is_null( $invalidMessageList ) || count($invalidMessageList) == 0 ){
			$defaultInvalidMsg = $this->defaultInvalidMessage( $requestKey );
			if( $emptyUseDefault && $this->isValid( $requestKey ) && !is_null( $defaultInvalidMsg ) ){
				return array( $defaultInvalidMsg );
			}
			return null;
		}
		return $invalidMessageList;
	}
	
	/**
	 * 全てのバリデータに失敗した箇所のメッセージのリスト全てを取得する
	 * Toytools_Viewからコールされます
	 * @return array
	 * @see Toytools_View
	 */
	public function getAllInvalidMessageList(){
		$return = array();
		$invalidMsgList = $this->_invalidKeyList;
		foreach( $invalidMsgList as $requestKey => $validList ){
			//$return[$requestKey] = $validList['invalid_message_list'];
			$return[$requestKey] = $this->getInvalidMessageList( $requestKey );
		}
		return $return;
	}
	
	
	/*
	 * バリデータに失敗した箇所のクラス名のリストを取得する
	 * @param	mixed バリデータのキー
	 * @return	null | array
	 * @description
	 * 			返却がnullであってもvalidであったとは限りません
	 * 			validかの判定はisValidを使用してください
	 */
	public function getInvalidClassList( $requestKey ){
		$invalidClassList = $this->_invalidKeyList[$requestKey]['invalid_class'];
		if( is_null( $invalidClassList ) || count($invalidClassList) == 0 ){
			return null;
		}
		return $invalidClassList;
	}
	
	/**
	 * デフォルトの共通バリデートメッセージを取得する
	 * @param	mixed バリデータのキー
	 * @return	null | string
	 */
	public function defaultInvalidMessage( $requestKey ){
		$defaultInvalidMsg = $this->_invalidKeyList[$requestKey]['default_invalid_message'];
		if( is_null($defaultInvalidMsg) ){
			return null;
		}
		return $defaultInvalidMsg;
	}
	
	//------------------- PRIVATES ------------------------------------------------------------------
	
	/**
	 * 
	 */
	private function _addInvalidMessage( $requestKey , $invalidMsg , $validateClass ){
		if( is_null($invalidMsg) || $invalidMsg == '' ){
			return;
		}
		array_push( $this->_invalidKeyList[$requestKey]['invalid_message_list']   , $invalidMsg );
		array_push( $this->_invalidKeyList[$requestKey]['invalid_class'] , $validateClass );
	}
}
?>