Pet*_*r M 10 php zend-framework zend-db zend-validate
我正在通过构建一些供我自己使用的实用程序网站来慢慢建立我的Zend技能.我一直在使用Zend Forms和Form验证,到目前为止我一直很高兴我已经理解了Zend的做事方式.但是我对如何在编辑表单的上下文中使用Zend_Validate_Db_NoRecordExists()以及映射到必须唯一的数据库列的字段感到困惑.
例如,使用这个简单的表
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
Run Code Online (Sandbox Code Playgroud)
如果我只是在Table Test中添加一个新行,我可以在Data字段的Zend Form元素中添加一个验证器:
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
Run Code Online (Sandbox Code Playgroud)
在表单验证时,此验证程序将检查表中是否已存在Data元素的内容.因此,插入Test可以继续而不违反数据字段UNIQUE限定符.
但是,编辑Test表的现有行时情况会有所不同.在这种情况下,验证器需要检查元素值是否满足两个互斥条件条件之一:
用户已更改元素值,表中当前不存在新值.
用户未更改元素值.因此,该值不当前存在的表(这是确定).
在Zend的验证文档谈论加入一个参数到NoRecordExists()验证从验证过程不包括记录的目的.想法是"验证表格以查找任何匹配的行,但忽略a字段具有此特定值的任何命中".这样的用例是在编辑表时验证元素所需的用例.在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) );
Run Code Online (Sandbox Code Playgroud)
问题是要被排除的值($ Value)在实例化时被绑定到验证器(也就是在实例化表单时).但是当表单正在编辑记录时,当表单最初填充数据时,该值需要绑定到$ data字段的内容 - IE最初从Test表行读取Data值.但是在典型的Zend模式中,表单被实例化并在两个单独的步骤中填充,这排除了将排除值绑定到期望的元素值.
下面的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
}
Run Code Online (Sandbox Code Playgroud)
我可以对Zend_Form进行子类化并覆盖populate()方法,以便在初始表单填充上一次性插入NoRecordExists()验证器,但这对我来说似乎是一个巨大的黑客攻击.所以我想知道其他人的想法,是否有一些模式已经写下来解决了这个问题?
编辑2009-02-04
我一直在想这个问题的唯一合适的解决方案是编写自定义验证器并忘记Zend版本.我的表单将记录ID作为隐藏字段,因此,根据表名和列名,我可以制作一些SQL来测试唯一性,并排除具有此类ID的行.当然,这开始让我思考如何将表单绑定到模型应该隐藏的dB层!
这就是它的完成方式:
$email->addValidator('Db_NoRecordExists', true, array('table' => 'user', 'field' => 'email'));
Run Code Online (Sandbox Code Playgroud)
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
Run Code Online (Sandbox Code Playgroud)
/* Don't check for Db_NoRecordExists if editing the same field */
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'user',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $this->request->get('id'))));
And after this you do verifications, e.g.:
if ($this->getRequest()->isPost())
{
if($form->isValid($this->getRequest()->getPost()))
{
....
Run Code Online (Sandbox Code Playgroud)
而已!