私は、自分で使用するためのユーティリティ Web サイトをいくつか構築することで、Zend のスキルをゆっくりと築き上げています。私は Zend Forms と Form validation を使用してきましたが、Zend のやり方を理解できたことに満足しています。しかし、Zend_Validate_Db_NoRecordExists() を編集フォームのコンテキストで使用する方法と、一意である必要があるデータベース列にマップするフィールドについて少し混乱しています。
たとえば、この単純なテーブルを使用して
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
テーブル テストに新しい行を追加するだけの場合は、データ フィールドの Zend フォーム要素にバリデーターを次のように追加できます。
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
フォームの検証時に、このバリデーターは Data 要素の内容がテーブルにまだ存在しないことを確認します。したがって、Test への挿入は、データ フィールドの UNIQUE 修飾子に違反することなく続行できます。
ただし、Test テーブルの既存の行を編集する場合は状況が異なります。その場合、バリデーターは、要素の値が相互に排他的な 2 つの条件のいずれかを満たすことを確認する必要があります。
ユーザーが要素の値を変更しましたが、新しい値は現在テーブルに存在しません。
ユーザーは要素の値を変更していません。したがって、値は現在テーブルに存在します (これは問題ありません)。
Zend Validation Docsでは、検証プロセスからレコードを除外する目的で NoRecordExists() バリデーターにパラメーターを追加することについて説明しています。「一致する行を探してテーブルを検証しますが、フィールドにこの特定の値があるヒットは無視する」という考えです。このような使用例は、テーブルの編集時に要素を検証するために必要なものです。1.9 でこれを行うための疑似コードは次のようになります (実際、これは 1.9 のソース コードから取得したものです。現在のドキュメントは間違っている可能性があります)。
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data',
array ('field'=>'Data', 'Value'=> $Value) );
問題は、除外される値 ($Value) がインスタンス化された時点で (フォームがインスタンス化された時点でも) バリデーターにバインドされることです。ただし、フォームがレコードを編集している場合、その値は、フォームに最初にデータが入力されたときの $data フィールドの内容にバインドする必要があります。つまり、Test テーブルの行から最初に読み取られたデータ値です。しかし、典型的な Zend パターンでは、フォームは 2 つの別々のステップでインスタンス化され、入力されます。これにより、除外値を目的の要素値にバインドすることができなくなります。
次の Zend 疑似コードは、$Value を NoRecordExists() バリデーターにバインドする場所を示しています (これは Zend コントローラーの一般的なパターンであることに注意してください)。
$form = new Form()
if (is Post) {
$formData = GetPostData()
if ($form->isValid($formData)) {
Update Table with $formData
Redirect out of here
} else {
$form->populate($formData)
}
} else {
$RowData = Get Data from Table
$form->populate($RowData) <=== This is where I want ('value' => $Value) bound
}
Zend_Form をサブクラス化し、populate() メソッドをオーバーライドして、最初のフォーム作成時に NoRecordExists() バリデーターをワンショット挿入することもできますが、それは私には大きなハックのように思えます。だから私は他の人がどう思うか知りたかったのですが、この問題を解決するパターンがすでに書き留められていますか?
2009-02-04 を編集
この問題に対する適切な解決策は、カスタム バリデータを作成し、Zend バージョンを忘れることだけだと私は考えています。私のフォームには非表示フィールドとしてレコード ID があるため、テーブル名と列名を指定して、一意性をテストし、そのような ID を持つ行を除外する SQL を作成できます。もちろん、これにより、モデルが非表示にするはずの dB レイヤーにフォームを結び付ける方法について考えるようになりました。