【问题标题】:How to use Zend_Validate twice如何使用 Zend_Validate 两次
【发布时间】:2013-05-10 20:48:20
【问题描述】:

我正在使用 Zend_Validate_Db_NoRecordExists,我想针对 DB 中的两个字段验证我的 Zend_Form,示例代码:

    $phone_1 = new Zend_Form_Element_Text('phone_1');
    $phone_1->addValidator(new Zend_Validate_Db_NoRecordExists(
                            array(
                                'field' => 'phone_1',
                                'table' => 'customer',
                    )))
            ->addValidator(new Zend_Validate_Db_NoRecordExists(
                            array(
                                'field' => 'phone_2',
                                'table' => 'customer',
                    )));

我能做到吗?

【问题讨论】:

  • 应该可以,你试过了吗?结果如何?你所有的记录都有2个电话号码吗?否则会有问题。
  • 正如我从Zend_Validate_Db_Abstract 看到的field 值应该是字符串,并且不会在任何地方过滤以包含任何无效字符。所以你可以尝试使用'field' => 'phone_1, phone_2'——它也应该可以工作。
  • 是的@RockyFord 我试过了,这个样本不再验证,即使是第一个。并非所有记录都有 2 个数字,有些只有 1 和 NULL 作为第二个。
  • @zeliboba 这种方式也没有奏效。我收到这条消息:“'字段列表'中的未知列'table.phone_1,phone2'”。
  • 你在谈论@RockyFord 的什么问题?提前谢谢你们。

标签: zend-framework zend-form zend-db zend-validate


【解决方案1】:

Create validation chain

$chain = new Zend_Validate();
$foo   = new Zend_Validate_Db_NoRecordExists(...);
$bar   = new Zend_Validate_Db_NoRecordExists(...);
$chain->addValidator($foo)
      ->addValidator($bar);

$element->addValidator($chain); 

更新@Bob Kruithof

使用 ZF 1.12.3 的快速而肮脏的示例。所有代码示例和行号均来自 ZF 1.12.3

<?php

$aPaths = array(
    'path/to/zf'
);

set_include_path(implode(PATH_SEPARATOR, $aPaths));

require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

$element = new Zend_Form_Element_Text('testSO');

$chain = new Zend_Validate();
$bar = new Zend_Validate_Regex('/^Test/');
$baz = new Zend_Validate_Regex('/Valid$/');
$chain->addValidator($bar)
      ->addValidator($baz);

$element->addValidator($chain); 

echo PHP_VERSION . ', ' . Zend_Version::getLatest() . PHP_EOL;

var_dump($element->isValid('Test'));
var_dump($element->isValid('Valid'));
var_dump($element->isValid('Test Valid'));

/* output
5.3.8, 1.12.3
bool(false)
bool(false)
bool(true)
*/

?>

为什么会这样:Zend_Form_Element.php 第 1144 - 1168 行通过 Zend_Validate 对象或字符串设置验证器。你是对的 - 如果验证器与名称一起使用,而不是作为链使用,那么结果就是一个验证器。但结果我们有:

$this->_validators[$name] = $validator;
/* debugger info:
    $name --> (string) Zend_Validate
    $validator --> Zend_Validate object {
  _validators => array(2) (
    [0] => array(2) (
      [instance] => Zend_Validate_Regex object {
      }
      [breakChainOnFailure] => (bool) false
    )
    [1] => array(2) (
      [instance] => Zend_Validate_Regex object {
      }
      [breakChainOnFailure] => (bool) false
    )
  )
  _messages => array(0)
  _errors => array(0)
  zfBreakChainOnFailure => (bool) false
}
*/

public function addValidator($validator, $breakChainOnFailure = false, $options = array())
    {
        if ($validator instanceof Zend_Validate_Interface) {
            $name = get_class($validator);

            if (!isset($validator->zfBreakChainOnFailure)) {
                $validator->zfBreakChainOnFailure = $breakChainOnFailure;
            }
        } elseif (is_string($validator)) {
            $name      = $validator;
            $validator = array(
                'validator' => $validator,
                'breakChainOnFailure' => $breakChainOnFailure,
                'options'             => $options,
            );
        } else {
            require_once 'Zend/Form/Exception.php';
            throw new Zend_Form_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface');
        }


        $this->_validators[$name] = $validator;

        return $this;
    }

当我们调用 $element-&gt;isValid()) 时,它会遍历链内的所有验证器 - 检查 Zend_Validate.php,第 91-110 行:

public function isValid($value)
    {
        $this->_messages = array();
        $this->_errors   = array();
        $result = true;
        foreach ($this->_validators as $element) {
            $validator = $element['instance'];
            if ($validator->isValid($value)) {
                continue;
            }
            $result = false;
            $messages = $validator->getMessages();
            $this->_messages = array_merge($this->_messages, $messages);
            $this->_errors   = array_merge($this->_errors,   array_keys($messages));
            if ($element['breakChainOnFailure']) {
                break;
            }
        }
        return $result;
    }

$this-&gt;_validators 是我们的验证器数组:

array(2) (
  [0] => array(2) (
    [instance] => Zend_Validate_Regex object {
      _messageTemplates => array(3) (
      )
      _messageVariables => array(1) (
      )
      _pattern => (string) /^Test/
      _value => null
      _messages => array(0)
      _obscureValue => (bool) false
      _errors => array(0)
      _translator => null
      _translatorDisabled => (bool) false
    }
    [breakChainOnFailure] => (bool) false
  )
  [1] => array(2) (
    [instance] => Zend_Validate_Regex object...

【讨论】:

  • 这永远不会起作用,因为验证器存储在关联数组中,其类名作为键值。
  • 实际上.. 这确实有效。这个解决方案比我的更优雅,应该被认为是问题的正确答案。
  • 验证器如果按名称设置,则存储在关联数组中。在那里你将它们设置为Zend_Validate() 对象,然后你可以这样使用它们。我会用另一个例子更新我的答案
  • 你是对的,BartekR。感谢您的详细解释。我把我的反对票变成了赞成票。
【解决方案2】:

Zend 将使用验证器的类名作为键将验证器添加到数组中的表单元素。这意味着如果您想添加两次相同的验证器但具有不同的规范,第二个验证器将覆盖第一个。

完成添加相同验证器的最简单且稍微有点混乱的方法是扩展验证器,以便第二个验证器接收不同的类名:

class NewValidator extends Zend_Validate_Db_NoRecordExists { }

现在您可以使用验证器两次:

$phone_1->addValidator(new Zend_Validate_Db_NoRecordExists(
                        array(
                            'field' => 'phone_1',
                            'table' => 'customer',
                )))
        ->addValidator(new NewValidator(
                        array(
                            'field' => 'phone_2',
                            'table' => 'customer',
                )));

这样就可以解决问题,而且比创建自定义验证器要快得多。

【讨论】:

    猜你喜欢
    • 2010-11-26
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多