Issues

ZF-8446: Zend_Filter_Input: Custom NotEmpty error message "inherited" by other NotEmpty validators

Issue Type: Patch Created: 2009-12-02T09:21:11.000+0000 Last Updated: 2011-07-26T18:23:26.000+0000 Status: Resolved Fix version(s): Reporter: Ryan Lange (ryan.lange) Assignee: Bart McLeod (mcleod@spaceweb.nl) Tags: - Zend_Filter_Input

Related issues: - ZF-11142

Attachments: - Input.php.patch

Description

Setting a custom error message for a NotEmpty validator in Zend_Filter_Input results in that custom error message being used for all following NotEmpty validators (if those validators don't themselves have custom error messages).

h3. Using Zend_Validate_NotEmpty

<pre class="highlight">
<?php

require 'Zend/Debug.php';
require 'Zend/Filter/Input.php';
require 'Zend/Validate/NotEmpty.php';

$data = array(
    'field1' => '',
    'field2' => ''
);

$validators = array(
    'field1' => array(
        new Zend_Validate_NotEmpty(),
        Zend_Filter_Input::MESSAGES => array(
            array(
                Zend_Validate_NotEmpty::IS_EMPTY => '\'field1\' is required'
            )
        )
    ),

    'field2' => array(
        new Zend_Validate_NotEmpty()
    )
);

$input = new Zend_Filter_Input( null, $validators, $data );

if( !$input->isValid() ) {
    Zend_Debug::dump( $input->getMessages() );
}



<pre class="highlight">
array(2) {
  ["field1"] => array(1) {
    ["isEmpty"] => string(20) "'field1' is required"
  }
  ["field2"] => array(1) {
    ["isEmpty"] => string(36) "Value is required and can't be empty"
  }
}



<pre class="highlight">
array(2) {
  ["field1"] => array(1) {
    ["isEmpty"] => array(1) {
      ["isEmpty"] => string(20) "'field1' is required"
    }
  }
  ["field2"] => array(1) {
    ["isEmpty"] => array(1) {
      ["isEmpty"] => string(20) "'field1' is required"
    }
  }
}

(The nested "isEmpty" arrays seem to be another issue with the customization of the NotEmpty error messages. Possibly related.)

This issue exists even when removing the NotEmpty validator from 'field2', falling back to Zend_Filter_Input's "built-in" NotEmpty validator.

Custom error messages for other validator types don't seem to suffer from this problem.

h3. Using Zend_Validate_EmailAddress

<pre class="highlight">
<?php

require 'Zend/Debug.php';
require 'Zend/Filter/Input.php';
require 'Zend/Validate/EmailAddress.php';

$data = array(
    'field1' => 'foo',
    'field2' => 'bar'
);

$validators = array(
    'field1' => array(
        new Zend_Validate_EmailAddress(),
        Zend_Filter_Input::MESSAGES => array(
            array(
                Zend_Validate_EmailAddress::INVALID_FORMAT => 'Improperly formatted email address \'%value%\' in \'field1\''
            )
        )
    ),

    'field2' => array(
        new Zend_Validate_EmailAddress()
    )
);

$input = new Zend_Filter_Input( null, $validators, $data );

if( !$input->isValid() ) {
    Zend_Debug::dump( $input->getMessages() );
}



<pre class="highlight">
array(2) {
  ["field1"] => array(1) {
    ["emailAddressInvalidFormat"] => string(52) "Improperly formatted email address 'foo' in 'field1'"
  }
  ["field2"] => array(1) {
    ["emailAddressInvalidFormat"] => string(74) "'bar' is not a valid email address in the basic format local-part@hostname"
  }
}

Comments

Posted by Ryan Lange (ryan.lange) on 2009-12-02T13:20:48.000+0000

Hmm... part of the issue here seems to be the fact that Zend_Filter_Input inserts its internal NotEmpty validator at the front of the validator chain and sets it to break the chain on failure.

<pre class="highlight">
921: $validatorChain = new Zend_Validate();
922: $validatorChain->addValidator($notEmptyValidator, true /* Always break on failure */);
923: $validatorChain->addValidator($validatorRule[self::VALIDATOR_CHAIN]);

A quick fix is to not break the chain on failure:

<pre class="highlight">
921: $validatorChain = new Zend_Validate();
922: $validatorChain->addValidator($notEmptyValidator);
923: $validatorChain->addValidator($validatorRule[self::VALIDATOR_CHAIN]);

The unfortunate side-effect of this is that, with the sample code in my OP, two NotEmpty validators are run on each value. It appears to work correctly because the "isEmpty" key gets reassigned by the second NotEmpty validator, which will be the developer-assigned one.

This also doesn't actually solve the "inheritance" issue for fields that rely on the internal NotEmpty validator.

<pre class="highlight">
<?php

require 'Zend/Debug.php';
require 'Zend/Filter/Input.php';
require 'Zend/Validate/NotEmpty.php';

$data = array(
    'field1' => '',
    'field2' => '',
    'field3' => ''
);

$validators = array(
    'field1' => array(
        new Zend_Validate_NotEmpty(),
        Zend_Filter_Input::MESSAGES => array(
            array(
                Zend_Validate_NotEmpty::IS_EMPTY => '\'field1\' is required'
            )
        )
    ),

    'field2' => array(
    ),

    'field3' => array(
    )
);

$input = new Zend_Filter_Input( null, $validators, $data );

if( !$input->isValid() ) {
    Zend_Debug::dump( $input->getMessages() );
}



<pre class="highlight">
array(2) {
  ["field1"] => array(1) {
    ["isEmpty"] => string(20) "'field1' is required"
  }
  ["field2"] => array(1) {
    ["isEmpty"] => string(50) "You must give a non-empty value for field 'field2'"
  }
  ["field3"] => array(1) {
    ["isEmpty"] => string(50) "You must give a non-empty value for field 'field3'"
  }
}



<pre class="highlight">
array(2) {
  ["field1"] => array(1) {
    ["isEmpty"] => string(20) "'field1' is required"
  }
  ["field2"] => array(1) {
    ["isEmpty"] => array(1) {
      ["isEmpty"] => string(20) "'field1' is required"
    }
  }
  ["field3"] => array(1) {
    ["isEmpty"] => array(1) {
      ["isEmpty"] => string(20) "'field1' is required"
    }
  }
}

The reason for this appears to be the following code:

<pre class="highlight">
780: if ($validator instanceof Zend_Validate_NotEmpty) {
781:     $this->_defaults[self::NOT_EMPTY_MESSAGE] = $value;
782: }

This simply takes the custom message of each developer-assigned NotEmpty validator and makes it the default empty message for Zend_Filter_Input. When a field has no NotEmpty validator of its own, and is empty, the internal NotEmpty validator ends up returning the custom message of the last, developer-assigned NotEmpty validator.

(Additionally, given the first sample code in my OP, $value will be an array here. This explains the nested "isEmpty" arrays I pointed out in the output in the OP.)

The fix here is to simply remove lines 780-782 (global defaults should never be transparently overwritten anyway). This fix, in conjunction with the minor fix to line 922, appears to fix the issues I've mentioned here. (NOTE: I've only done limited testing so far. This may create other issues I haven't come across yet. The potential double-run of NotEmpty validators I mentioned above is still an issue, though.)

Posted by Ryan Lange (ryan.lange) on 2009-12-02T13:34:00.000+0000

I apologize for talking to myself here, but...

On second thought, my suggested change to line 922 in my previous comment completely undoes the entire reason for having the ALLOW_EMPTY option, since the entire validator chain will now run regardless of the emptiness of the value.

Hmm... I'll wait for additional comments.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-03-27T21:01:36.000+0000

I linked this issue, there is a patch available in the linked issue.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-03-27T21:02:36.000+0000

The patch is in the related issue. So far I found three issues reporting the same problem with the inherited error messages.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-03-28T10:14:27.000+0000

Fix is in svn now.

Posted by Ryan Lange (ryan.lange) on 2011-03-28T20:14:09.000+0000

I can confirm that the patch attached to ZF-11142 does indeed fix the inherited error message issue. The nested error message issue is still present, but since that now appears to be unrelated[1], I think this issue can be considered closed. I don't seem to have permission to update the status myself, though, so someone else will have to do the honors.

Thanks, Bart!

-- [1] If a separate issue doesn't already exist for this, I'll go ahead and create one.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-03-28T20:21:53.000+0000

Closed by permission of the reporter.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-04-08T08:08:51.000+0000

Reopening to attach patches for the nested error message.

As usual, I will leave this issue open for a week for the community and the component owner to review the patches.

If no one has complained after a week, I will commit the patch for the component and the patch for the UnitTest.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-04-08T08:10:05.000+0000

Added the patches.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-04-08T08:11:15.000+0000

Changed to minor, because these patches are only to fix the nested error messages. The other issue, with the inherited error messages, is already fixed in svn.

Posted by Bart McLeod (mcleod@spaceweb.nl) on 2011-04-12T11:22:53.000+0000

The fix for the nested error messages is in svn now.

Posted by Thomas Weidner (thomas) on 2011-07-26T18:23:26.000+0000

Fixed in ZF2 with GH-268

Have you found an issue?

See the Overview section for more details.

Copyright

© 2006-2016 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.

Contacts