我正在通过构建一些供我自己使用的实用程序网站来慢慢增强我的 Zend 技能。我一直在使用 Zend Forms 和表单验证,到目前为止,我很高兴我已经了解了 Zend 的做事方式。然而,我对如何在编辑表单和映射到必须唯一的数据库列的字段的上下文中使用 Zend_Validate_Db_NoRecordExists() 有点困惑。
例如使用这个简单的表
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
如果我只是向表测试添加一个新行,我可以向 Zend Form 元素的数据字段添加一个验证器,如下所示:
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
在表单验证时,该验证器将检查数据元素的内容是否已存在于表中。因此,可以继续插入到 Test 中,而不会违反数据字段 UNIQUE 限定符。
然而,当编辑测试表的现有行时,情况有所不同。在这种情况下,验证器需要检查元素值是否满足两个互斥条件之一:
用户已更改元素值,并且新值当前未更改
存在于表中。
用户有Not改变了元素值。因此价值does当前存在于表中(这是可以的)。
The Zend 验证文档 http://framework.zend.com/manual/en/zend.validate.set.html讨论向 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 字段的内容 - 即最初从测试表行读取的数据值。但在典型的 Zend 模式中,表单是在两个单独的步骤中实例化和填充的,这阻止了将排除值绑定到所需的元素值。
以下 Zend psuedo 代码标记了我希望将 $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 作为隐藏字段,因此给定表名和列名,我可以编写一些 SQL 来测试唯一性并排除具有此类 ID 的行。当然,这让我开始思考如何将表单绑定到模型应该隐藏的 dB 层!