我正在通过构建一些供我自己使用的实用程序网站来慢慢建立我的Zend技能。我一直在使用Zend Forms和Form验证,到目前为止我一直很高兴我已经理解了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') )
在表单验证时,此验证程序将检查表中是否已存在Data元素的内容。因此,插入Test可以在不违反数据字段UNIQUE限定符的情况下继续。
但是,在编辑Test表的现有行时,情况会有所不同。在这种情况下,验证器需要检查元素值是否满足两个互斥条件条件之一:
用户已更改元素值,当前不会显示新值 存在于表格中。
用户不更改了元素值。因此,表中当前存在值 (这没关系)。
Zend Validation Docs谈到将参数添加到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) );
问题是要被排除的值($ 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
}
我可以对Zend_Form进行子类化并覆盖populate()方法,以便在初始表单填充上一次性插入NoRecordExists()验证器,但这对我来说似乎是一个巨大的黑客攻击。所以我想知道其他人的想法,是否有一些模式已经写下来解决了这个问题?
修改2009-02-04
我一直在想这个问题的唯一合适的解决方案是编写一个自定义验证器而忘记Zend版本。我的表单将记录ID作为隐藏字段,因此,根据表名和列名,我可以制作一些SQL来测试唯一性,并排除具有此类ID的行。当然,这开始让我思考如何将表单绑定到模型应该隐藏的dB层!
答案 0 :(得分:6)
这就是它的完成方式:
$email->addValidator('Db_NoRecordExists', true, array('table' => 'user', 'field' => 'email'));
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
/* 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()))
{
....
就是这样!
答案 1 :(得分:4)
这也有效:
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
array('Db_NoRecordExists', true, array(
'table' => 'guestbook',
'field' => 'email',
'messages' => array(
'recordFound' => 'Email already taken'
)
)
)
)
));
答案 2 :(得分:1)
在回顾了压倒性的反应后,我决定使用自定义验证器
答案 3 :(得分:1)
答案 4 :(得分:1)
private $_id;
public function setId($id=null)
{
$this->_id=$id;
}
public function init()
{
.....
if(isset($this->_id)){
$email->addValidator('Db_NoRecordExists', false, array('table' => 'user', 'field' => 'email','exclude' => array ('field' => 'id', 'value' => $this->_id) ));
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
}
现在你可以使用:
$form = new Form_Test(array('id'=>$id));
答案 5 :(得分:0)
您只需拨打$form->getElement('input')->removeValidator('Zend_Validator_Db_NoRecordExists');
,而不是提供排除。
答案 6 :(得分:0)
我刚刚尝试了email address
唯一性的这个例子,它与以下内容完美配合:
1]以我的形式:
// Add an email element
$this->addElement('text', 'email', array(
'label' => 'Email :',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
我需要为unique email address
添加一些特殊功能:
$email = new Zend_Form_Element_Text('email');
$email->addValidator('Db_NoRecordExists', true, array('table' => 'guestbook', 'field' => 'email'));
2]在我的控制器中:
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'guestbook',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $request->get('id'))));
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
希望它可以帮助你们!
由于