Empty Values Passed to Zend Framework 2 Validators

Empty values passed to Zend framework 2 validators

Following works for ZF2 version 2.1.1:

The problem (if I got it correctly) is that in following example, for empty values of 'fieldName', no validation is triggered. This can be quite annoying, though in

$input = new \Zend\InputFilter\Input('fieldName');

$input
->setAllowEmpty(true)
->setRequired(false)
->getValidatorChain()
->attach(new \Zend\Validator\Callback(function ($value) {
echo 'called validator!';

return true; // valid
}));

$inputFilter = new \Zend\InputFilter\InputFilter();
$inputFilter->add($input);

$inputFilter->setData(array('fieldName' => 'value'));
var_dump($inputFilter->isValid()); // true, echoes 'called validator!'

$inputFilter->setData(array('fieldName' => ''));
var_dump($inputFilter->isValid()); // true, no output

$inputFilter->setData(array());
var_dump($inputFilter->isValid()); // true, no output

This is quite annoying when you have particular cases, like checking an URL assigned to a page in your CMS and avoiding collisions (empty URL is still an URL!).

There's a way of handling this for empty strings, which is to basically attach the NotEmpty validator on your own, and avoiding calls to setRequired and setAllowEmpty. This will basically tell Zend\InputFilter\Input#injectNotEmptyValidator not to utomatically attach a NotEmpty validator on its own:

$input = new \Zend\InputFilter\Input('fieldName');

$input
->getValidatorChain()
->attach(new \Zend\Validator\NotEmpty(\Zend\Validator\NotEmpty::NULL))
->attach(new \Zend\Validator\Callback(function ($value) {
echo 'called validator!';

return true; // valid
}));

$inputFilter = new \Zend\InputFilter\InputFilter();
$inputFilter->add($input);

$inputFilter->setData(array('fieldName' => 'value'));
var_dump($inputFilter->isValid()); // true, echoes 'called validator!'

$inputFilter->setData(array('fieldName' => ''));
var_dump($inputFilter->isValid()); // true, echoes 'called validator!'

$inputFilter->setData(array());
var_dump($inputFilter->isValid()); // false (null was passed to the validator)

If you also want to check against null, you will need to extend Zend\InputFilter\Input as following:

class MyInput extends \Zend\InputFilter\Input
{
// disabling auto-injection of the `NotEmpty` validator
protected function injectNotEmptyValidator() {}
}

ZF2 input validator for required not empty only when not null

Yes, you ought to use NotEmpty validator.

$inputFilter = new \Zend\InputFilter\InputFilter ();
$inputFilter->add ([
'name' => 'foo',
'validators' => [
[
'name' => 'not_empty',
'options' => [
'type' => 'string'
]
]
]
]);

$form->setInputFilter ($inputFilter);

Zend framework - how to allow empty field for form element

$freetext = $this->CreateElement('textarea', 'freetext')
->addValidator('StringLength', false, array(10,500))
->setRequired(false);

Your code should already do that, the setRequired(false) method do what you're asking for, i.e. if the value is not submitted then validators won't be run.

Do you have any issue with the code you've written, some validation error messages or something else?

Update

I've changed the setRequired() to true - I want to allow empty string as an acceptable value on a require field.

What is the semantic in setRequired(true) and allowing the empty string as a valid value? Or better what do you require if the element can be empty?

What you've asked in the edit is a no sense, because if an element is required it MUST have a value different from the empty string. If you need to accept the empty string as a valid value just use setRequired(false). When you get form values with Zend_Form::getValues() or Zend_Form_Element::getValue() you'll obtain the empty string as result.

Anyway here it's the explanation of setRequired and setAllowEmpty from ZF manual:

Using the defaults, validating an Element without passing a value, or
passing an empty string for it, skips all validators and validates to
TRUE.

  • setAllowEmpty(false) leaving the two other mentioned flags
    untouched, will validate against the validator chain you defined for
    this Element, regardless of the value passed to isValid().

  • setRequired(true) leaving the two other mentioned flags untouched,
    will add a 'NotEmpty' validator on top of the validator chain (if none
    was already set)), with the $breakChainOnFailure flag set. This
    behavior lends required flag semantic meaning: if no value is passed,
    we immediately invalidate the submission and notify the user, and
    prevent other validators from running on what we already know is
    invalid data.


If you do not want this behavior, you can turn it off by passing a
FALSE value to setAutoInsertNotEmptyValidator($flag); this will
prevent isValid() from placing the 'NotEmpty' validator in the
validator chain.

ZF2 - Validator chain not running on empty elements

After a whole day of looking into this, I've found a route around the problem.

First off, the Zend\InputFilter\BaseInputFilter class contains the following for 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;
}

As allowEmpty was true for my Input, the validation for that Input stops and moves on to the next Input element in the array. Changing allowEmpty to false on my Input solves that issue, but creates another, as the 'Zend\InputFilter\Input' class calls the following function during it's isValid() function:

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;
}

Because my field is required and allowEmpty is now false, a 'NotEmpty' validator is added to my chain automatically. Once that was discovered, the solution was simple. I created an 'Input' class in my custom library, which overrides the injectNotEmptyValidator function, forcing it to do nothing:

namespace Si\InputFilter;

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

Doing the above menas that 'NotEmpty' is NOT added to my validator chain, so my XOR validator can run correctly. All I have to do now is use my corrected Si\InputFilter\Input class to populate InputFilter for those two elements.

Hope that helps.

Zend Framework notEmpty validator setRequired

I agree that this is a little confusing. The reason is that all form elements have an allowEmpty flag (true by default), that skips validation if the value is blank. It works this way because otherwise, adding validators to optional elements would be a real pain, e.g.:

$dateOfBirth = new Zend_Form_Element_Text('dob');
$dateOfBirth->setLabel('Date of birth (optional)');
$dateOfBirth->addValidator(new Zend_Validate_Date());
$form->addElement($dateOfBirth);

this would always fail validation if the user chose not to enter their DOB, as '' is not a valid date. With the allowEmpty flag on by default it works as you would expect (it only validates the date when one has been entered).

Calling setRequired(true) adds a NotEmpty validator but it also sets the allowEmpty flag to false. I would recommend you stick with this approach. Alternatively you can get your way to work by setting the flag as well:

$username = new Zend_Form_Element_Text('txtUsername');
$username->addValidator(new Zend_Validate_NotEmpty());
$username->setAllowEmpty(false);

Validator not working in Zend Framework 2

I think you missed something in the documentation tutorial. Your code is wrong.

You have :

'validators' => array(
array('name' => 'StringLength',
'encoding' => 'UTF-8',
'min' => 5,
'max' => 35

)

)

You should have this :

'validators' => array (
array (
'name' => 'StringLength',
'options' => array (//<-----options array here
'encoding' => 'UTF-8',
'min' => 1,
'max' => 100
)
)
)

The min, max and encoding should be in the options array.

Conditionally required in Zend Framework's 2 InputFilter

First of all, you may want to enable validation on empty/null values as of Empty values passed to Zend framework 2 validators

You can use a callback input filter as in following example:

$filter = new \Zend\InputFilter\InputFilter();
$type = new \Zend\InputFilter\Input('type');
$smth = new \Zend\InputFilter\Input('smth');

$smth
->getValidatorChain()
->attach(new \Zend\Validator\NotEmpty(\Zend\Validator\NotEmpty::NULL))
->attach(new \Zend\Validator\Callback(function ($value) use ($type) {
return $value || (1 != $type->getValue());
}));

$filter->add($type);
$filter->add($smth);

This will basically work when the value smth is an empty string and the value for type is not 1. If the value for type is 1, then smth has to be different from an empty string.



Related Topics



Leave a reply



Submit