モデルで文字列の長さをvalidateする際にテーブルのカラムサイズを使う方法です。
CakePHPではモデルがテーブルのカラム情報を保持しているのですが、この情報にはカラム名やデータ型の他にカラムサイズ(varchar(N)等)も含まれています。
そこでモデルのvalidateでこの値を使えば最低限テーブルのカラムに収まるかどうかはチェックできます。
ここでは以下のようなテーブルでnameとemailの文字列長をチェックします。(DBはPostgreSQL)
create table users ( id serial primary key ,name varchar(50) not null ,email varchar(100) not null );
1. AppModelにカラムサイズ取得、文字列長チェックメソッドを追加する
AppModelにカラムサイズ取得用メソッド(getColumnLength)と文字列長チェックメソッド(validatesLength)を記述します。
<?php
class AppModel extends Model {
/**
* Returns the column type of a column length in the model
*
* @param string $column The name of the model column
* @return integer
* @access public
*/
function getColumnLength($column) {
$columns = $this->loadInfo();
$columns = $columns->value;
$cols = array();
foreach($columns as $col) {
if ($col['name'] == $column) {
return $col['length'];
}
}
return null;
}
/**
* valid value length
*
* @param array $data
* @param string $fields
* @access public
*/
function validatesLength($data, $fields) {
foreach ($fields as $v) {
$len = $this->getColumnLength($v);
if (!empty($data[$v]) && mb_strlen($data[$v]) > $len) {
$this->invalidate($v . '_len_' . $len);
}
}
}
}
?>
2. モデルで文字列長をチェックする
モデルで文字列長チェックを呼びます。単に$dataとvalidatesLengthメソッドにチェックするカラムを配列で渡すだけでokです。
validatesLength内部ではテーブルのカラムサイズで文字列長チェックを行い、エラーならinvalidateメソッドを呼びます。このinvalidateメソッドに与える値[カラム名 + ‘_len_’ + カラムサイズ]がポイントです。これをモデルの$validationErrorsに持たせておくことにより、ビューで正規の文字列長を含んだエラーメッセージを動的に出力することができます。
<?php
function validates($data = array()) {
if (!parent::validates($data)) {
return false;
}
if (empty($data)) {
$data = $this->data;
}
$data = $data['User'];
// 文字列長チェック
$list = array('name', 'email');
$this->validatesLength($data, $list);
}
?>
3. HtmlExtヘルパでエラーメッセージを出力
文字列長エラーメッセージを動的に出力するメソッド(tagLengthErrorMsg)をHtmlヘルパーを継承したHtmlExtに定義しておきます。
<?php
class HtmlExtHelper extends HtmlHelper {
/**
* lengthエラーメッセージ表示
*
* @param string $field
* @param string $name
* @return string
*/
function tagLengthErrorMsg($field, $name) {
if (empty($this->validationErrors)) {
return null;
}
$this->setFormTag($field);
foreach ($this->validationErrors[$this->model] as $k => $v) {
if (preg_match("/^" . $this->field . "_len_([0-9]+)$/", $k, $m)) {
$message = sprintf("%sは%d文字以内で入力してください。", $name, $m[1]);
return $this->tagErrorMsg($field . "_len_" . $m[1], $message);
}
}
return null;
}
}
?>
4. ビューテンプレートでヘルパ呼び出し
最後にビューテンプレートで先程のtagLengthErrorMsgメソッドを呼び出します。これは引数としてカラム名とエラーメッセージ用項目名を与えます。
<!-- エラー時は「氏名は50文字以内で入力して下さい。」を表示 -->
<?php echo $htmlExt->tagLengthErrorMsg('User/name', '氏名'); ?>
<!-- エラー時は「メールアドレスは100文字以内で入力して下さい。」を表示 -->
<?php echo $htmlExt->tagLengthErrorMsg('User/email', 'メールアドレス'); ?>
ソース内に文字列長を書かなくて良い
この方法では文字列長をテーブル定義から取得するので、ソースに文字列長を書く必要がありません。もしテーブルのカラムサイズが変わってもソースはそのままで新しいカラムサイズに対応することができます。
(ちなみにtext型などカラムサイズが無いものについてはテーブル定義情報(モデルの$_tableInfo)に直接文字列長を入れるという方法もあります。)
ここでは1.1系で記述していますが、1.2系ではvalidateが柔軟な形になっているので2.のモデルでのチェックはもうちょっとスマートに書けそうです。
- Newer: CakePHP 比較演算子インジェクションに注意
- Older: PHPによる攻撃コードが出現–GIFファイルに隠される?
トラックバック:0
- このエントリーのトラックバックURL
- /blog/2007/06/cakephp_validate_length.html/trackback
- Listed below are links to weblogs that reference
- CakePHP テーブルのカラムサイズでvalidate from Shin x blog

