Issues

ZF-5788: The documentation on the use of Zend_Form_Element::setRequired(), ::setAllowEmpty() and the 'NotEmpty' Validator is fuzzy and misleading

Issue Type: Patch Created: 2009-02-15T04:22:36.000+0000 Last Updated: 2010-04-16T14:17:03.000+0000 Status: Resolved Fix version(s): - 1.10.4 (28/Apr/10)

Reporter: Michael Ekoka (verysimple) Assignee: Christian Albrecht (alab) Tags: - Zend_Form

Related issues: Attachments:

Description

http://framework.zend.com/manual/en/…

The section explaining the use of Zend_Form_Element::setRequired(), ::setAllowEmpty() and the 'NotEmpty' validator lacks clarity. Asking for an explanation about it in IRC just confirmed to me that this particular process is misunderstood. I had to dig into the code itself to understand what's actually going on. This is what the manual says:

{quote} In addition to validators, you can specify that an element is required, using setRequired(true). By default, this flag is false, meaning that your validator chain will be skipped if no value is passed to isValid(). {quote}

1-) My first issue with this section is that setRequired() should not be introduced here. Much more clarity would be achieved by first discussing setAllowEmpty() and the 'NotEmpty' Validation rule, because setRequired() is a redundant feature. The same effect can be obtained by explicitly setting the 'allowEmpty' flag to false and explicitly adding the 'NotEmpty' validation to the chain. setRequired() is nothing more than a convenience method, a shortcut. It only has influence when the flag is set to true, in which case it does 2 things: - it ignores the 'allowEmpty' flag (acting as if allowEmpty had been set to false). Therefore it is important to understand what the allowEmpty flag does to understand how setRequire() influences the behavior of the form. - it adds a 'NotEmpty' validator to the validation chain, (provided that the Zend_Form_Element::$autoInserNotEmptyValidator flag is set to true). As for the allowEmpty flag it would be better to understand what the NotEmpty validation rule does. AFAICT, it has no other purpose.

  1. Unlike stated in that little paragraph, setRequired(false) does not imply that the validators chain will be skipped when an empty value is passed to isValid(). That behavior is controlled by the 'allowEmpty' flag, which remains unaffected when the 'required' flag is set to false. setRequired(false) simply deactivate the shortcut mentioned earlier in point 1. When the 'required' flag is set to false, there is no more bypassing the allowEmpty flag and no implicit addition of the 'NotEmpty' validator to the chain.

{quote} By default, when an element is required, a flag, 'allowEmpty', is also true. This means that if a value evaluating to empty is passed to isValid(), the validators will be skipped. You can toggle this flag using the accessor setAllowEmpty($flag); when the flag is false, then if a value is passed, the validators will still run. {quote}

  1. Again, the wording is misleading. setRequired(true), sets the 'required' flag to true, but has no direct influence on the 'allowEmpty' flag itself. It doesn't set allowEmpty to false, it simply acts as if allowEmpty was false (see point 1 and 2). Instead the paragraph should have explained how allowEmpty influences validation behavior and how setting 'required' to true changes that behavior.

setAllowEmpty(true) allows an element to skip validation when populated with an empty value. Setting the 'required' flag to true on an element will ignore that property of the allowEmpty flag, without changing the flag itself. The allowEmpty flag is useful for non mandatory fields (empty value acceptable), that still need to be checked for proper format when a value is provided. The flag is not part of the validation chain, but modifies the validation behavior for the element.

Comments

Posted by Michael Ekoka (verysimple) on 2009-02-23T20:01:34.000+0000

edited for clarity

Posted by Christian Albrecht (alab) on 2010-04-07T03:29:53.000+0000

In addition to validators, you can specify that an element is required, using setRequired($flag). By default, this flag is FALSE. In combination with setAllowEmpty($flag) (TRUE by default) and setAutoInsertNotEmptyValidator($flag) (TRUE by default), the behavior of your validator chain can be modified in a number of ways:

  • Using the default Flags, 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 it was not already added), 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.
<pre class="highlight">
Index: documentation/manual/en/module_specs/Zend_Form-Elements.xml
===================================================================
--- documentation/manual/en/module_specs/Zend_Form-Elements.xml (Revision 21783)
+++ documentation/manual/en/module_specs/Zend_Form-Elements.xml (Arbeitskopie)
@@ -619,30 +619,37 @@
 
         
             In addition to validators, you can specify that an element is
-            required, using setRequired(true). By default, this
-            flag is FALSE, meaning that your validator chain will be skipped if
-            no value is passed to isValid(). You can modify this
-            behavior in a number of ways:
+            required, using setRequired($flag). By default, this
+            flag is FALSE. In combination with 
+            setAllowEmpty($flag) (TRUE
+            by default) and setAutoInsertNotEmptyValidator($flag)
+            (TRUE by default), the behavior of your validator chain
+            can be modified in a number of ways:
         
-                    By default, when an element is required, a flag,
-                    'allowEmpty', is also TRUE. This means that if a value
-                    evaluating to empty is passed to isValid(), the
-                    validators will be skipped. You can toggle this flag using
-                    the accessor setAllowEmpty($flag); when the
-                    flag is FALSE and a value is passed, the validators
-                    will still run.
+                    Using the defaults, validating an Element without passing a value, or
+                    passing an empty string for it, skips all validators and validates to
+                    TRUE.
                 
-                    By default, if an element is required but does not contain
-                    a 'NotEmpty' validator, isValid() will add one
-                    to the top of the stack, with the
+                    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

Posted by Christian Albrecht (alab) on 2010-04-07T06:30:22.000+0000

Reading in the sources, this is somewhat mixing responsibilities, what about throwing setAutoInsertNotEmptyValidator() away, in the favour of just using setRequired() in combination with setAllowEmpty() ?

<pre class="highlight">
    public function isValid($value, $context = null)
    {
        $this->setValue($value);
        $value = $this->getValue();

        if ((('' === $value) || (null === $value))
            && !$this->isRequired()
            && $this->getAllowEmpty()
        ) {
            return true;
        }

        if ($this->isRequired()
            && !$this->getAllowEmpty() // && $this->autoInsertNotEmptyValidator()
            && !$this->getValidator('NotEmpty'))
        {
            $validators = $this->getValidators();
            $notEmpty   = array('validator' => 'NotEmpty', 'breakChainOnFailure' => true);
            array_unshift($validators, $notEmpty);
            $this->setValidators($validators);
        }
...

Posted by Christian Albrecht (alab) on 2010-04-07T13:38:12.000+0000

After talking to Matthew, i finally got the concept why setAutoInsertNotEmptyValidator was introduced, with my solution in the previous comment the one call to setRequired(true) which is obviously a shortcut for convenience would be achieved by setRequired(true) && setAllowEmpty(false).

//edit What made me struggle a while is the following, as a side-effect, setAllowEmpty(false) while leaving the other flags default, will be the same as setRequire(true) and setAutoInsertNotEmptyValidator(false), which is a bit confusing because of the naming.

So just changing the Documentation is enough, everything else i can think of would remove Choices which is probably a bad thing to do.

Posted by Matthew Weier O'Phinney (matthew) on 2010-04-16T13:12:53.000+0000

Patch applied in trunk and 1.10 release branch

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