我创建了一个自定义验证器,需要填写“门牌号码”或“公寓号码”,但不能同时填写(异或)。
如果两个字段都已填写(失败),或者一个字段已填写(通过),则验证器可以正常工作。但如果两个字段都为空,验证器根本不会运行。
这是两个元素的输入过滤器规范:
$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/