validation - ZF2 - 验证器链未在空元素上运行

标签 validation zend-framework2 xor

我创建了一个自定义验证器,需要填写“门牌号码”或“公寓号码”,但不能同时填写(异或)。

如果两个字段都已填写(失败),或者一个字段已填写(通过),则验证器可以正常工作。但如果两个字段都为空,验证器根本不会运行。

这是两个元素的输入过滤器规范:

$input = new Input('flat_number');
$input->setRequired(true);
$input->setAllowEmpty(true);
$input->setValue($this->flatNumber);
$input->getValidatorChain()
        ->addValidator(new \Si\Validator\HouseFlatCheck('house_number'))
        ->addValidator(new \Zend\Validator\StringLength(array('max' => 30)));
$input->getFilterChain()->attach($this->defaultFilterChain);
$inputFilter->add($input);

$input = new Input('house_number');
$input->setRequired(true);
$input->setAllowEmpty(true);
$input->setValue($this->houseNumber);
$input->getValidatorChain()
        ->addValidator(new \Si\Validator\HouseFlatCheck('flat_number'))
        ->addValidator(new \Zend\Validator\StringLength(array('max' => 30)));
$input->getFilterChain()->attach($this->defaultFilterChain);
$inputFilter->add($input);

从表面上看,如果字段为空并满足“required”和“allowEmpty”要求,验证器就不会运行。

有什么方法可以让“HouseFlatCheck”验证器针对我的两个元素运行,尽管两个字段都是空的?

最佳答案

经过一整天的研究,我找到了解决该问题的方法。

首先,Zend\InputFilter\BaseInputFilter 类包含 isValid() 的以下内容:

public function isValid()
{
    if (null === $this->data) {
        throw new Exception\RuntimeException(sprintf(
            '%s: no data present to validate!',
            __METHOD__
        ));
    }

    $this->validInputs   = array();
    $this->invalidInputs = array();
    $valid               = true;

    $inputs = $this->validationGroup ?: array_keys($this->inputs);
    foreach ($inputs as $name) {
        $input = $this->inputs[$name];
        if (!array_key_exists($name, $this->data)
            || (null === $this->data[$name])
            || (is_string($this->data[$name]) && strlen($this->data[$name]) === 0)
        ) {
            if ($input instanceof InputInterface) {
                // - test if input is required
                if (!$input->isRequired()) {
                    $this->validInputs[$name] = $input;
                    continue;
                }
                // - test if input allows empty
                if ($input->allowEmpty()) {
                    $this->validInputs[$name] = $input;
                    continue;
                }
            }
            // make sure we have a value (empty) for validation
            $this->data[$name] = '';
        }

        if ($input instanceof InputFilterInterface) {
            if (!$input->isValid()) {
                $this->invalidInputs[$name] = $input;
                $valid = false;
                continue;
            }
            $this->validInputs[$name] = $input;
            continue;
        }
        if ($input instanceof InputInterface) {
            if (!$input->isValid($this->data)) {
                // Validation failure
                $this->invalidInputs[$name] = $input;
                $valid = false;

                if ($input->breakOnFailure()) {
                    return false;
                }
                continue;
            }
            $this->validInputs[$name] = $input;
            continue;
        }
    }

    return $valid;
}

由于我的输入的allowEmpty为true,因此该输入的验证将停止并移至数组中的下一个输入元素。将输入上的allowEmpty更改为false可以解决该问题,但会产生另一个问题,因为“Zend\InputFilter\Input”类在其isValid()函数期间调用以下函数:

protected function injectNotEmptyValidator()
{
    if ((!$this->isRequired() && $this->allowEmpty()) || $this->notEmptyValidator) {
        return;
    }
    $chain = $this->getValidatorChain();

    // Check if NotEmpty validator is already first in chain
    $validators = $chain->getValidators();
    if (isset($validators[0]['instance'])
        && $validators[0]['instance'] instanceof NotEmpty
    ) {
        $this->notEmptyValidator = true;
        return;
    }

    $chain->prependByName('NotEmpty', array(), true);
    $this->notEmptyValidator = true;
}

因为我的字段是必填字段,并且 allowedEmpty 现在为 false,所以“NotEmpty”验证器会自动添加到我的链中。一旦发现这一点,解决方案就很简单了。我在自定义库中创建了一个“Input”类,它覆盖了injectNotEmptyValidator 函数,强制它不执行任何操作:

namespace Si\InputFilter;

class Input extends \Zend\InputFilter\Input {
    protected function injectNotEmptyValidator() {
        return;
    }
}

执行上述操作后,“NotEmpty”不会添加到我的验证器链中,因此我的 XOR 验证器可以正确运行。我现在要做的就是使用更正后的 Si\InputFilter\Input 类来填充这两个元素的 InputFilter。

希望有帮助。

关于validation - ZF2 - 验证器链未在空元素上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14454927/

相关文章:

java - 无法触发构造函数级别验证

php - 用户名验证不起作用

javascript - 添加相同规则的多个字段

php - Behat - 未找到上下文类。

Ruby,二进制字符串中的随机字节异或

php - XOR PHP 中的一个字符串,键是一个整数

java - 如何用编译时泛型验证替换运行时instanceof检查

php - 从 Zend Framework 2 在 mysql 中插入 BIT 列

zend-framework2 - 使用 ZF3 在模块 Bootstrap 中无法访问 View 助手管理器

python - 尝试完成 Google foo.bar 级别 3 (queue_to_do) 并继续超过时间限制