Empty values passed to Zend framework 2 validators
Asked Answered
L

5

13

How can I pass an empty value through Zend framework 2 ValidatorChain to my custom validator?

It was possible on ZF1 by allowEmpty(false)

On ZF2 with empty element value :

  • If allowEmpty = false, NotEmptyValidator is added to the top of ValidatorChain with breakOnFailure = true, @see Zend/InputFilter/Input#injectNotEmptyValidator.

  • If allowEmpty = true, Element is considered as Valid, @see Zend/InputFilter/BaseInputFilter#isValid

    if ($input->allowEmpty()) {
        $this->validInputs[$name] = $input;
        continue;
    }
    
Litigant answered 16/2, 2013 at 12:45 Comment(7)
akrabat.com/zend-framework-2/…Blindfold
It's not what i need because if allow_empty = true and my element value is empty, zf2 consider that element is Valid and will not invoke validators.Litigant
I think i don't understand your problem then. Either you allow empty values or you don't. If you don't allow empty values, all validators will run, otherwise validation will fail, when an empty input is given. If you do allow them, an empty value doesn't need to be validated any further oOBlindfold
Ok to simplify description, how can i, with zf2, applicate a custom validator on a field even if it's empty.Litigant
Simplifying isn't the way to go. What do you want to validate? "" is empty - there is no validation for that. It's an empty string, what the heck do you want to validate with this? It just makes not the slightest sense. What EXACTLY do you want to do?Blindfold
Thanks for your attention, I'm trying to migrate application from ZF1 to ZF2. I need to do validations for field A depending on the value of field B. I used jeremykendall.net/2008/12/24/… and it's required allow_empty=false for pass empty value to validator. On ZF2 this trick don't work because allow_empty = true add a NotEmptyValidator on top of ValidatorChain.Litigant
My solution is to create a custom Input class which overrides the injectNotEmptyValidator function, and forcing it to do nothing: class CustomInput extends \Zend\InputFilter\Input { protected function injectNotEmptyValidator() { return; } } <br/> This means that NotEmptyValidator will not added to my validator chain, so my validator can run correctly. All I have to do now is use my CustomInput class to populate InputFilter for element to validate. i'm not sure if it's the best way.Litigant
S
14

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() {}
}
Schwejda answered 16/2, 2013 at 21:47 Comment(3)
You've go it,I want to check against null and empty, so your last solution confirms my implementation. Thanks a lot.Litigant
Just do $input->setContinueIfEmpty(true); instead of extending Zend\InputFilter\Input, it will have the same effect, less work and more simple.Tierell
NotEmpty::NULL - this helped. For those who uses fogetInputFilterSpecification() with arrays you need the following structure: 'validators' => [[ 'name' => NotEmpty::class, 'options' => [ 'type' => NotEmpty::NULL ]]]'Timely
C
27

continue_if_empty solved my problem. Thanks to @dson-horácio-junior. This is what I used:

$this->add(array(
    'name' => 'field',
    'continue_if_empty' => true,
    'filters' => array(
        array('name' => 'StripTags'),
        array('name' => 'StringTrim')
    ),
    'validators' => array(
        array(
            'name' => 'Application\Form\Validator\Sample'
        )
    )
));

public function isValid($value, $context = null)
{
    if ($value == '' && $context['otherfield'] == '') {
        $this->error(self::INVALID_FIELD);

        return false;
    }

    // ...
}
Calices answered 8/7, 2014 at 12:55 Comment(2)
Best answer! Deserves more upvotes. If you set continue_if_empty to true then the InputFilter\Factory does not automatically add a NotEmpty validator, so all validation goes to the user defined validators.Cyanohydrin
i took 30 minutes to find this option THANKS a lotDenoting
S
14

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() {}
}
Schwejda answered 16/2, 2013 at 21:47 Comment(3)
You've go it,I want to check against null and empty, so your last solution confirms my implementation. Thanks a lot.Litigant
Just do $input->setContinueIfEmpty(true); instead of extending Zend\InputFilter\Input, it will have the same effect, less work and more simple.Tierell
NotEmpty::NULL - this helped. For those who uses fogetInputFilterSpecification() with arrays you need the following structure: 'validators' => [[ 'name' => NotEmpty::class, 'options' => [ 'type' => NotEmpty::NULL ]]]'Timely
F
7

This triggered validation of my Callback validator when the value was an empty string:

'required'          => false,
'allow_empty'       => false,
'continue_if_empty' => true,
'validators'        => array(
    array(
        'name'    => 'Callback',
        'options' => array(
            'callback' => function ($value, $context = []) use ($self) {
                // ...
            }
        )
    )
)

The allow_empty initially invalidates the empty string and the continue_if_empty allows it to then be evaluated by the validators that follow.

Foreandaft answered 7/11, 2014 at 18:43 Comment(0)
E
2

If you like to use a separate form validate class or a array notation for validate, you can do as follows:

$factory     = new Zend\InputFilter\Factory();
$inputFilter = new Zend\InputFilter\InputFilter();

$inputFilter->add($factory->createInput(array(
    'name' => 'name',
    'required' => false,
    'allowEmpty' => true,
    'filters' => array(
        array('name' => 'StripTags'),
        array('name' => 'StringTrim'),
    ),
    'validators' => array(
        array(
            'name' => 'StringLength',
            'options' => array(
                'encoding' => 'UTF-8',
                'min' => '8',
                'max' => '100',
            ),
        ),
    ),
)));

You can pass an array with required => false and allowEmpty => true to input filter factory (as I remember you can pass it directly to input filter too - not so sure).

Enunciation answered 26/2, 2014 at 9:35 Comment(0)
T
2

I see often the people making the mistake using allowEmpty in the inputFilter config arrays. The string should be written with underscore separation not with camel case. So allow_empty will work:

'fieldName' => array(
    'name'        => 'fieldName',
    'required'    => true,
    'allow_empty' => true,
    'filters' => array(
        //... your filters ...
    )
    'validators' => array(
        //... your validators ...
    ),
);

meaning a field with key 'fieldName' must be present in the data, but its value is allowed to be empty.

Transformer answered 11/2, 2015 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.