Home > Tags > validate

validate

[cakephp1.2]CakePHP1.2.0.7296 RC2用DRYなエラーメッセージ出力を一部修正しました。[validate]

以前のエントリー[cakephp1.2]CakePHP1.2.0.7296 RC2用DRYなエラーメッセージ出力。[validate]
で載せていた【app/models/app_model.php】内のinvalidFieldsファンクション内で
validate設定の”required”を考慮したコードになっていなかったので修正しました。

[cakephp1.2]CakePHP1.2.0.7296 RC2用DRYなエラーメッセージ出力。[validate]に修正済のコードを載せておきました。

[cakephp1.2]CakePHP1.2.0.7296 RC2用DRYなエラーメッセージ出力。[validate]

※ 2008/10/22追記
【app/models/app_model.php】内のinvalidFieldsファンクション内でvalidate設定の”required”を考慮したコードになっていなかったので修正しました。適当なコード載っけてすみません。

以前にngtnさんのvalidationのメッセージ出力をDRYにしてみるっていうエントリーを見てから、CakePHP1.2ではずっとDRYなエラーメッセージ出力を使わせてもらってたんですが、CakePHPのバージョンを1.2.0.7296 RC2にすると動かなくなってしまいました。

で、動くようにしてみましたよ。偉そうにいうほどの修正量じゃありませんが・・・
修正したのは【app/app_model.php】のみです。全部載っけておきます。

< ?php
config('messages');
class AppModel extends Model {
	var $db = null;
	function __construct() {
		parent::__construct();
		$this->db =& ConnectionManager::getDataSource($this->useDbConfig);
	}
 
	function escape($data=null) {
		return $this->db->value($data);
	}
 
	//テーブル名のゲッタ
	function getTableName() {
		return $this->name;
	}
	//重複チェックのバリデート
	function checkDuplicate($data) {
		$cond = array(key($data) => '= '.current($data));
		if(($id = $this->getID()) !== false){
			$cond[$this->getTableName().'.id'] = '!= '.$id;
		}
		return ($this->findCount($cond) === 0) ? true : false;
	}
 
	/**
	 * invalidFieldsメソッドのオーバーライド
	 *
	 * @param array $data Parameter usage is deprecated, set Model::$data instead
	 * @return array Array of invalid fields
	 * @access public
	 */
	function invalidFields($options = array()) {
		if (!$this->Behaviors->trigger($this, 'beforeValidate', array($options), array('break' => true, 'breakOn' => false)) || $this->beforeValidate($options) === false) {
			return $this->validationErrors;
		}
 
		if (!isset($this->validate) || empty($this->validate)) {
			return $this->validationErrors;
		}
		$data = $this->data;
		$methods = array_map('strtolower', get_class_methods($this));
		$behaviorMethods = array_keys($this->Behaviors->methods());
 
		if (isset($data[$this->alias])) {
			$data = $data[$this->alias];
		} elseif (!is_array($data)) {
			$data = array();
		}
 
		$Validation =& Validation::getInstance();
		$this->exists();
 
		foreach ($this->validate as $fieldName => $ruleSet) {
			if (!is_array($ruleSet) || (is_array($ruleSet) && isset($ruleSet['rule']))) {
				$ruleSet = array($ruleSet);
			}
			$default = array('allowEmpty' => null, 'required' => null, 'rule' => 'blank', 'last' => false, 'on' => null);
 
			foreach ($ruleSet as $index => $validator) {
				if (!is_array($validator)) {
					$validator = array('rule' => $validator);
				}
				$validator = array_merge($default, $validator);
 
				if (isset($validator['message'])) {
					$message = $validator['message'];
				} else {
					$message = __('This field cannot be left blank', true);
				}
 
				$messageParams = array();
				if(isset($validator['message_params'])) {
					$messageParams = $validator['message_params'];
				}
 
				if (empty($validator['on']) || ($validator['on'] == 'create' && !$this->__exists) || ($validator['on'] == 'update' && $this->__exists)) {
					if ((!isset($data[$fieldName]) && $validator['required'] === true) || (isset($data[$fieldName]) && (empty($data[$fieldName]) && !is_numeric($data[$fieldName])) && $validator['allowEmpty'] === false)) {
						$this->invalidate($fieldName, $message, $messageParams);
						if ($validator['last']) {
							break;
						}
					} elseif (array_key_exists($fieldName, $data)) {
						if (empty($data[$fieldName]) && $data[$fieldName] != '0' && $validator['allowEmpty'] === true) {
							break;
						}
						if (is_array($validator['rule'])) {
							$rule = $validator['rule'][0];
							unset($validator['rule'][0]);
							$ruleParams = array_merge(array($data[$fieldName]), array_values($validator['rule']));
							$messageParams = array_values($validator['rule']); 
						} else {
							$rule = $validator['rule'];
							$ruleParams = array($data[$fieldName]);
							$messageParams = array();
						}
						if ( array_key_exists($rule, Messages::$error)) {
							$message = Messages::$error[$rule];
							$validator['message'] = $message;
						}
 
						$valid = true;
 
						if (in_array(strtolower($rule), $methods)) {
							$ruleParams[] = array_diff_key($validator, $default);
							$ruleParams[0] = array($fieldName => $ruleParams[0]);
							$valid = $this->dispatchMethod($rule, $ruleParams);
						} elseif (in_array($rule, $behaviorMethods) || in_array(strtolower($rule), $behaviorMethods)) {
							$ruleParams[] = array_diff_key($validator, $default);
							$ruleParams[0] = array($fieldName => $ruleParams[0]);
							$valid = $this->Behaviors->dispatchMethod($this, $rule, $ruleParams);
						} elseif (method_exists($Validation, $rule)) {
							$valid = $Validation->dispatchMethod($rule, $ruleParams);
						} elseif (!is_array($validator['rule'])) {
							$valid = preg_match($rule, $data[$fieldName]);
						}
						if (!$valid) {
							if (!isset($validator['message'])) {
								if (is_string($index)) {
									$validator['message'] = $index;
								} else {
									$validator['message'] = ife(is_numeric($index) && count($ruleSet) > 1, ($index + 1), $message);
								}
							}
							$this->invalidate($fieldName, $validator['message'], $messageParams);
 
							if ($validator['last']) {
								break;
							}
						}
					}
				}
			}
		}
		return $this->validationErrors;
	}
 
	/**
	 * invalidateのオーバーライド
	 *
	 * @param string $field The name of the field to invalidate
	 * @param string $value Name of validation rule that was not met
	 * @access public
	 */
	function invalidate($field, $value = null, $messageParams = array()) {
		if (!is_array($this->validationErrors)) {
			$this->validationErrors = array();
		}
		if (empty($value)) {
			$value = true;
		}
		if (count($messageParams) > 0) {
			$value = vsprintf($value, $messageParams);
		}
		// 既にセットしてある場合は、区切り文字を挟んで連結する
		if (!empty($this->validationErrors[$field])) {
			$this->validationErrors[$field] .= Messages::$separator . $value;
		} else {
			$this->validationErrors[$field] = $value;
		}
	}
}
?>

こんだけです。いちおう他のスクリプトも。
【app/config/messages.php】

< ?php
class Messages {
	/**
	 * メッセージの区切り文字
	 *
	 * @var string
	 */
	static $separator = "<br />";
 
	/**
	 * validationルールに対応するエラーメッセージ
	 *
	 * @var array
	 */
	static $error = array(
		VALID_NOT_EMPTY	=> '必ず入力してください。',
		VALID_NUMBER 	=> '半角数字を入力してください。',
		VALID_EMAIL 	=> 'メールアドレス形式で入力してください。',
		VALID_YEAR 	=> '年(1000~2999)を入力してください。',
		'alphaNumeric' 	=> '半角英数字を入力してください。',
		'between' 	=> '%1$d文字以上%2$d文字以内の半角数字を入力してください。',
		'blank' 		=> '空でなければなりません。',
		'cc' 		=> 'クレジットカード番号として正しくありません。',
		'comparison' 	=> '入力値%1$s%2$sを満たす値を入力してください。',
		'custom' 		=> '入力値が正しくありません。',
		'date' 		=> '日付形式(%1$s)で入力してください。',
		'decimal' 	=> '小数点第%1$d位までの半角数字を入力してください。',
		'email' 		=> 'メールアドレス形式で入力してください。',
		'equalTo' 	=> '入力値が"%1$s"と一致しません。',
		'extension' 	=> '拡張子が正しくありません。',
		'file' 		=> '',	// 実装されていない
		'ip' 		=> 'IPアドレス形式で入力してください。',
		'minLength' 	=> '%1$d文字以上で入力してください',
		'maxLength' 	=> '%1$d文字以内で入力してください',
		'money' 		=> '入力値が正しくありません。',// 通貨?		
		'multiple' 	=> '',	// 実装されていない
		'numeric' 	=> '半角数字を入力してください。',
		'phone' 		=> '電話番号形式で入力してください。',
		'postal' 		=> '郵便番号形式で入力してください。',
		'range' 		=> '%1$dより大きく%2$dより小さい半角数字を入力してください。',
		'ssn' 		=> 'ソーシャルセキュリティナンバー形式で入力してください。',
		'url' 		=> 'URL形式で入力してください。',
		'userDefined' 	=> '入力値が正しくありません。',
	);
}
?>

【app/views/helpers/app_form.php】

< ?php
class AppFormHelper extends FormHelper {
	/**
	 * errorメソッドのオーバーライド
	 *
	 * @param string $field A field name, like "Modelname.fieldname", "Modelname/fieldname" is deprecated
	 * @param string $text		Error message
	 * @param array $options	Rendering options for <div /> wrapper tag
	 * @return string If there are errors this method returns an error message, otherwise null.
	 * @access public
	 */
	function error($field, $text = null, $options = array()) {
		$this->setEntity($field);
		$options = array_merge(array('wrap' => true, 'class' => 'error-message', 'escape' => false), $options);
 
		if ($error = $this->tagIsInvalid()) {
			if (is_array($text) && is_numeric($error) && $error > 0) {
				$error--;
			}
			if (is_array($text) && isset($text[$error])) {
				$text = $text[$error];
			} elseif (is_array($text)) {
				$text = null;
			}
 
			if ($text != null) {
				$error = $text;
			} elseif (is_numeric($error)) {
				$error = sprintf(__('Error in field %s', true), Inflector::humanize($this->field()));
			}
			if ($options['escape']) {
				$error = h($error);
				unset($options['escape']);
			}
			$messages = explode(Messages::$separator, $error);
			$output = '';
			foreach ( $messages as $message){
				if ($options['wrap'] === true) {
					unset($options['wrap']);
					$output .= $this->output(sprintf($this->Html->tags['error'], $this->_parseAttributes($options), $message));
					$options['wrap'] = true;
				} else {
					$output .= $message;
				}
			}
			return $output;
		} else {
			return null;
		}
	}	
}
?>

【app/controllers/app_controller.php】

<php class AppController extends Controller {
	var $helpers = array('Html', 'Form', 'AppForm');
}
?>
</php>

以上です。使いかたはngtnさんの

validationのメッセージ出力をDRYにしてみるっていうエントリーを見てください。 Continue reading

[cakephp]テーブル未使用モデルで$this->Model->create()するとエラー吐くよ。

Modelで

var $useTable = false;

という設定をして、

$this->Model->create($this->data);

をすると、

Warning (512): (Model::getColumnType) Unable to locate model field data. If you are using a model without a database table, try implementing schema() [CORE/cake/libs/model/model.php, line 959]
Code | Context
 
$column	=	"how_know"
$cols	=	array()
 
$cols = $this->schema();
if (empty($cols)) {
    trigger_error(__('(Model::getColumnType) Unable to locate model field data. If you are using a model without a database table, try implementing schema()', true), E_USER_WARNING);
 
Model::getColumnType() - CORE/cake/libs/model/model.php, line 959
Model::deconstruct() - CORE/cake/libs/model/model.php, line 857
Model::set() - CORE/cake/libs/model/model.php, line 839
Model::create() - CORE/cake/libs/model/model.php, line 1014
PartnersController::regist() - APP/controllers/partners_controller.php, line 20
Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 265
Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 237
[main] - APP/webroot/index.php, line 84

というエラーを吐いてきたんですよ。
エラー見ると、

$this->data["Model"]["how_know"]

という要素に格納されている値に問題あるみたいですね。
ちなみに、セレクトボックスと選択したした値(配列)が格納されています。

で、色々と調べてみると、Tableを使ってはいなくても、TableのSchema情報を定義しておけ、と。
つーことでModelを再設定します。

var $useTable = false;
var $_schema = array("how_know"=>array("type"=>"string"));

これでエラーを吐かなくなりました。

[cakephp1.2]validate使用時の注意。[validate]

cakephp1.1の時のように、

$this->yourmodel->validates($this->data);

とすると、cakephp1.2では

(Model::validates) Parameter usage is deprecated, set the $data property instead
Warning (512): [CORE/cake/libs/model/model.php, line 1647]

とWarningを吐きます。1.2では下記のようにしましょう。

if ($this->YourModel->create($this->data) && $this->YourModel->validates()) {
    // validation ok
} else {
    // validation not ok
}

また、新規登録時のvalidateルールを下記の様に設定するとする。

	var $validate = array(
				"name"=>array(
					array("rule"=>VALID_NOT_EMPTY)
				),
				"kana"=>array(
					array("rule"=>VALID_NOT_EMPTY)
				)
			)

でも、データ更新時にはvaidateルールから
「kana」のvalidateルールを除きたい場合は、

unset($this->YourModel->validate['kana']);

と書くよ。

Home > Tags > validate