Zend 验证 Db_NoRecordExists 和排除选项

7
我正在尝试使用“排除”选项来进行Db_NoRecordExists验证器,因为当我“编辑”元素时,它总是返回“重复”的错误,这很常见。
我的目的是告诉表单从控制器中保留传递给表单本身的值...
以下是控制器内容:
public function editAction()
{
$id = $this->getRequest()->getParam('id');
$pagesMapper = new Application_Model_PagesMapper();
$form = new Application_Form_PageEdit();
$form->populate($pagesMapper->fetchId($id, true));
if ($this->getRequest()->isPost()) {
    if ($form->isValid($this->getRequest()->getPost())) {
        //... cut ...
    }
}
$this->view->form = $form;
}

这是表单:

class Application_Form_PageEdit extends Zend_Form
{
public function init()
{
$commonFilters      = array('StringTrim');
$commonValidators = array('NotEmpty');
    $this->setMethod('post')->setAction('/admin-page/edit');

$id = new Zend_Form_Element_Hidden('id');
$pid = new Zend_Form_Element_Hidden('pid');

$keyname = new Zend_Form_Element_Text('keyname');
$keyname->setLabel('Keyname')
    ->setRequired(true)
    ->addFilters($commonFilters)
    ->addFilter('StringToLower')
    ->addFilter('Word_SeparatorToDash')
    ->addValidator('Db_NoRecordExists', false, array(
        'table'     => 'pages',
        'field'     => 'keyname',
        'exclude'   => array(
            'field' => 'id',
            'value' => $this->getValue('id)
        )
        )
    );

//...剪切...

有一些建议吗?

6个回答

17

我曾遇到类似的问题。我的解决方法是将验证器从init函数移动到isValid函数中。

public function isValid($data)
{
  $this->getElement('keyname')
       ->addValidator(
           'Db_NoRecordExists',
           false,
           array(
               'table'     => 'pages',
               'field'     => 'keyname',
               'exclude'   => array(
                   'field' => 'id',
                   'value' => $this->getValue('id')
               )
           )
       );
  return parent::isValid($data);
}

我在思考,认为在init()方法中获取值是愚蠢的,因为元素尚未应用于表单,因此无法填写并将永远返回false :D我会尝试这个。 - MiPnamic
当我添加验证器时,“id对象”存在,但仍未“连接”到表单...它只是init方法内的变量...还没有添加到“$this”...我认为这不是一个错误,而是我的问题,因为init方法构造整个表单,但表单在“populate()”之前不包含任何数据,所以验证器将过滤空值(因为它未被填充,所以id值为空)...这就是为什么必须在override方法中完成此类具有动态值的验证(在我看来)。 - MiPnamic
谢谢您提供的解决方案,但我想知道为什么是'value' => $this->getValue('id')而不是'value' => data['id']?谢谢。 - user648198
在他的表单中,他创建并传递了一个ID给一个元素。我想这个元素的值不会改变,因此他可以从中检索该值。话虽如此,data['id']也可以起作用。 - Richard Parnaby-King
1
感谢您提供的解决方案。问题是,“isValid”函数是否仍在“../application/forms/MyForm.php”文件中? - marienke
我在使用$this->getValue('username')时遇到了问题,但$data['username']可以正常工作。 - hobbs

2

对我来说,只有这个解决方案完美地起作用:

public function isValid($data)
{
    $clause    = $this->_dbAdapter->quoteInto('id = ?', $this->getValue('id'));
    $this->getElement('keyname')
        ->addValidator('Db_NoRecordExists', false, array(
            'adapter'   =>  $this->_dbAdapter,
            'table'     => 'employee_name',
            'field'     => 'name',
            'exclude'   => $clause
        )
    );
    return parent::isValid($data);
}

1
$this->_dbAdapter = Zend_Db_Table::getDefaultAdapter(); 这行代码是用于获取默认的Zend数据库适配器。 - max4ever

1
我不喜欢覆盖 isValid() 函数的解决方案。这感觉就像我们不理解 Db_NoRecordExists 验证器是如何工作的。您只需要在调用 isValid() 之前向验证器提供要排除的记录的实际 ID 即可。该验证器甚至提供了一种访问器,在其中设置此值!Zend 的说明也没有提供足够的帮助,所以人们很难解决这个问题。
以下是一种更优雅和面向工作流程的设置排除项而无需修改、扩展或覆盖表单的方法:
// $post is assumed to have our posted form variables // 
// $form is assumed to be our form that is already setup with validators. //

$form->getElement('username')->
        getValidator('Db_NoRecordExists')->
        setExclude([
            'field' => 'user_id',
            'value' => $post['user_id'],
        ]);

if ( $form->isValid( $post ) ) {
    // do valid stuff
    // ...
}
else {
    // do invalid stuff
    // ...
}

排除实际上是我们字段和值的数组。在调用 isValid() 之前,我们只需告诉验证器要排除什么即可。完成了。简单明了。

我要补充的是,在这里讨论的所有解决方案中,包括我的解决方案,排除的值本身并没有经过验证。该值将被发送到一个数据库语句。为了保持警惕,需要在将排除值分配给exclude之前,通过一个特别设计的验证器对其进行验证。小心谨慎总是没错的。 - WebTigers

1
在控制器中进行验证逻辑之前,我会添加以下代码来检查字段是否与当前用户数据匹配。如果匹配,则将验证器从元素中移除,如下所示:
    if(($this->getRequest()->isPost()) && $request->getParam('email')==$this->user->getEmail()) {
        $form_preferences->getElement('email')->removeValidator('Db_NoRecordExists');
    }

在那个时候,它将毫无问题地通过isValid逻辑。

if(($this->getRequest()->isPost()) && $form_preferences->isValid($_POST)) {

享受!


0

将此更改应用于表单:

class Application_Form_PageEdit extends Zend_Form
{
    public function getExcludeFromQuery($elementName)
    {
        $element = $this->getElement($elementName);
        if ($element)
        {
            return $element->getValidator('Db_NoRecordExists')->getExclude();
        } else
        {
            return NULL;
        }
    }

    public function setExcludeFromQuery($elementName, $excludeFromQuery)
    {
        $element = $this->getElement($elementName);
        if ($element)
        {
            $element->getValidator('Db_NoRecordExists')->setExclude($excludeFromQuery);
        }
        return $this;
    }


    public function init()
    {
    $commonFilters      = array('StringTrim');
    $commonValidators = array('NotEmpty');
        $this->setMethod('post')->setAction('/admin-page/edit');

    $id = new Zend_Form_Element_Hidden('id');
    $pid = new Zend_Form_Element_Hidden('pid');

    $keyname = new Zend_Form_Element_Text('keyname');
    $keyname->setLabel('Keyname')
        ->setRequired(true)
        ->addFilters($commonFilters)
        ->addFilter('StringToLower')
        ->addFilter('Word_SeparatorToDash')
        ->addValidator('Db_NoRecordExists', false, array(
            'table'     => 'pages',
            'field'     => 'keyname',
            'exclude'   => array(
                'field' => 'id',
                'value' => $this->getValue('id)
            )
            )
        );

至于编辑操作:

public function editAction()
{
$duplicateElementName = 'whatever';
$duplicateElementValue = 'value from db';

$id = $this->getRequest()->getParam('id');
$pagesMapper = new Application_Model_PagesMapper();
$form = new Application_Form_PageEdit();
$form->populate($pagesMapper->fetchId($id, true));

$form->setExcludeFromQuery($duplicateElementName, $duplicateElementValue);

if ($this->getRequest()->isPost()) {
    if ($form->isValid($this->getRequest()->getPost())) {
        //... cut ...
    }
}
$this->view->form = $form;
}

0

isValid 函数中无需构建验证器,只需更新 exclude 子句:

public function isValid($data)
{
    $this->getElement('name')->getValidator('Db_NoRecordExists')->setExclude('id != ' . $data['id']);
    return parent::isValid($data);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接