Zend_Validate_Db_NoRecordExists で特定の条件で除外する
データベース上に既にデータが登録されているかを Zend_Validate_Db_NoRecordExists を使えば、他のバリデーションと一緒に使用できるので凄く便利。
これが新規登録とかだと、何も考えずに入力された値チェックするように書けば良い。
Users テーブルの name カラムに既に存在するかどうかチェック
<?php $name = 'hoge'; $validator = new Zend_Validate_Db_NoRecordExists('users', 'name'); $ret = $validator->isValid($name);
これで 'hoge' ユーザが存在するかチェックをしてくれる。
これが更新系の場合だと、例えば name はそのまま更新せず、email を更新したいという場合に使うと name は既に存在していると、エラーを返えしてくる。
その場合は特定のレコードを除外して重複チェックをするというオプションがある。
Zend_Validate_Db_RecordExists および Zend_Validate_Db_NoRecordExists には、 テーブルの一部を除外してその内容を調べる方法があります。 where 句を文字列で指定するか、あるいはキー "field" および "value" を含む配列を指定します。
http://framework.zend.com/manual/ja/zend.validate.set.html#zend.validate.db.excluding-records
除外条件を配列で指定すると、!= 演算子を使用します。 つまり、テーブル内の残りのレコードの内容を確認してからレコードを変更できるのです (たとえばユーザ情報のフォームなどで使用します)。
ドキュメントには上記の用に書いてあり、サンプルコードも載っている。
<?php $validator = new Zend_Validate_Db_NoRecordExists( array( 'table' => 'users', 'field' => 'username', 'exclude' => array( 'field' => 'id', 'value' => $user_id ) ) ); if ($validator->isValid($username)) { // ユーザ名は有効なようです } else { // ユーザ名が無効なので、その理由を表示します $messages = $validator->getMessages(); foreach ($messages as $message) { echo "$message\n"; } }上の例は、id = $user_id であるレコードを除いてそのテーブル内に $username を含むレコードが存在しないことを調べます。
http://framework.zend.com/manual/ja/zend.validate.set.html#zend.validate.db.excluding-records
が、このサンプルのままやっても動かない。
なぜなら、第一引数は確かに配列を受ける事ができるが、あくまでテーブル名とスキーマのみとなっている。
Zend_Validate_Db_Abstract のコンストラクタは以下のようになってる。
<?php public function __construct($table, $field, $exclude = null, Zend_Db_Adapter_Abstract $adapter = null) { if ($adapter !== null) { $this->_adapter = $adapter; } $this->_exclude = $exclude; $this->_field = (string) $field; if (is_array($table)) { $this->_table = (isset($table['table'])) ? $table['table'] : ''; $this->_schema = (isset($table['schema'])) ? $table['schema'] : null; } else { $this->_table = (string) $table; } } }
というわけで、特定の条件を除外したい場合は、以下のように書けばいける。
<?php $id = 1; $exclude = array( 'field' => 'id', 'value' => $id ); $validator = new Zend_Validate_Db_NoRecordExists('users', 'name', $exclude); $ret = $validator->isValid($name);
これで id = 1 のレコードを除いて重複チェックが書けられるようになる。
ところでこれってドキュメントのバグ?英語版もそうなってたし、仕様変更になったのが追いついてないのか、ドキュメントが正しくて実装が間違ってるのか…。
ちなみに Zend Framework のバージョンは最新の 1.93PL1。
追記 2009/10/04 23:00
Issue Tracker に報告してみた。
Issue - Zend Framework