Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_FilterChain Zend_Validator Component Proposal

Proposed Component Name Zend_FilterChain Zend_Validator
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_FilterChain Zend_Validator
Proposers Christopher Thompson, author
Darby Felton, Zend liaison
Revision 1.1 - 25 June 2006: Created. (wiki revision: 11)

Table of Contents

1. Overview

Zend_FilterChain is a class to apply any number and/or combination of Filter objects to data in a container. Zend_Validator is a class to apply any number and/or combination of Rule objects to data in a container. Typically these are applied to the data in a Request container as part of a Input or Form Controller.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • FilterChain class allows any number and/or combination of Filter objects to be added to the chain
  • Filter classes are polymorphic allowing unlimited variety of custom filters
  • FilterChain applies filters to specified data in the container passed to it
  • Validator class allows any number and/or combination of Rule objects to be added to the chain
  • Rule classes are polymorphic allowing unlimited variety of custom rules, each defining an error message
  • Validator applies rules to specified data in the container passed to it and returns the error messages for failed rules
  • Validator itself implements the Rule interface so may be used as a Rule

4. Dependencies on Other Framework Components

  • Zend_Exception

5. Theory of Operation

OVERVIEW

The FilterChain/Validator style is an alternative to the simpler InputFilter style. The InputFilter is excellent where you want direct access to filtered data. Its procedural style is very easy to use. Conversely, the FilterChain/Validator style provides a foundation for things like Form and Application Controllers. These allow the programmer to be more focused on specifying the Rules and Filters needed and lets the controller deal with the actual program flow. They also ease creating scaffolding.

The thing I immediately noticed about the InputFilter class is that it is really a Container. That is one of its strengths. Containers tie frameworks together. The most common PHP Container is keyed access to data, which is the class/object form of PHP's associative arrays. Filters and Validators need a simple Container to provide structured access to data. The Container needed has only the bare bones capabilities taken from the InputFilter's constructor and get raw data methods.

The simple Container class, probably something like Zend_Http_Request would be the usual container used. This Container could be enhanced by implementing the magic accessor functions, but I have kept it simple in the example.

The FilterChain and Validator need polymorphic Filters and Rules. In the example I split-up the current Zend_Filter class into a separate class for each Filter and Rule – with doFilter() and isValid() methods respectively. These can be separated the Filters and Rules into two separate files or into a separate file for each Filter and Rule.

It should be noted that the classes presented here are the minimal case and that additional list management or other functionality may easily be added. Also note that the current Filter and InputFilter class could easily be build on top of these individual Filter and Rule classes to centralize tests.

6. Milestones / Tasks

zone: Missing {zone-data:milestones}

7. Class Index

  • Zend_Filter_Abstract.php
  • Zend_Filter_*.php
  • Zend_Rule_Abstract.php
  • Zend_Rule_Abstract.php
  • Zend_Validator.php
  • Zend_Filterchain.php

8. Use Cases

FILTERCHAIN

VALIDATOR

  • it should be noted that combining the above two example is the basis for a Form Controller class

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jun 27, 2006

    <p>I would like to propose this structure instead of single getErrorMsg() method:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    // get errors for all keys or for one exactly specified key. returns array
    public function getErrors($key = null);

    // first and one only error for particular key. returns string or null
    public function getError($key = null);
    ]]></ac:plain-text-body></ac:macro>

    1. Jun 27, 2006

      <p>Those would probably be a good change. I have found that when using these classes I sometimes want an array but most of the time I just want a concatenated string of all the errors to display. So maybe:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      // get errors for all keys or for one exactly specified key. returns array
      public function getErrors($key = null);

      // get errors for all keys or for one exactly specified key. returns string (imploded error array)
      public function getErrorMsgs($key = null, $join=', ');
      ]]></ac:plain-text-body></ac:macro>

      1. Jun 28, 2006

        <p>Well, I was kind of hoping you would implement the one you have just ommited. I mean the one which returns only the first error for a key as a string. Actually I'm using <em>only</em> this one throughout my apps.</p>

        1. Jun 28, 2006

          <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$view->error = array_shift($validator->getErrors("key"));]]></ac:plain-text-body></ac:macro>

          <p>Magic! <ac:emoticon ac:name="wink" /></p>

          <p>Although now I look like an ass because I'm going to suggest this:</p>

          <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
          public function getErrorList($separator = "\n")
          {
          return implode($separator, $this->getErrors());
          }
          ]]></ac:plain-text-body></ac:macro>

          <p>e.g.,</p>

          <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
          // In controller
          $view->errors = $this->getErrorList("</li>\n<li>");

          // In template
          <div id="errors">
          The following errors were encountered:
          <ul>
          <li><?php print $view->errors; ?></li>
          </ul>
          </div>
          ]]></ac:plain-text-body></ac:macro>

          <p>Also, addRule should have a default error message for each that can be overwritten by passing a user-defined one.</p>

          <p>Zend_Rule_Int() - "{$value} is not an integer"<br />
          Zend_Rule_Email() - "{$value} is not a valid e-mail address"<br />
          Zend_Rule_Range(10, 20) - "{$value} is not a valid number between {$valueFrom} and {$valueTo}"</p>

          1. Jun 28, 2006

            <p>I think the idea of default error messages is a good one. </p>

          2. Oct 16, 2006

            <p>I like all the ideas above. </p>

            <p>One problem that plagues the validator is the topic of error messages and I18N. I'd like to see the validator make use of a View template for the error message. Templates could then be added or overridden for different languages or context.</p>

        2. Jun 28, 2006

          <p>You may be right Michael. My quick edit was just to add the ability to get joined strings because they are what gets used most in things like Forms. Getting just the first error would be a good and easy addition. </p>

  2. Jun 27, 2006

    <p>Can we vote for proposals somewhere? This one surely deserves some votes <ac:emoticon ac:name="smile" /></p>

  3. Jun 28, 2006

    <p>I'd also put in a vote for this one</p>

  4. Jun 29, 2006

    <p>There's a powerful feature I've used in similar filter/validator chain classes in the past where the rules return more than just a yes/no answer:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    class Zend_Rule_*
    {
    // Definitive 'no' answer; no need to consult any other rules in the chain.
    const DENY;

    // Definitive 'yes' answer; skip any remaining rules in the chain.
    const ACCEPT;

    // Neither 'yes' or 'no'. Consult the other rules in the chain for a definitive answer.
    const NEUTRAL;

    // Returns as an answer one of the constants above. Usually returns NEUTRAL.
    public function validate($value) {}
    }
    ]]></ac:plain-text-body></ac:macro>

    <p>If all of the rules in the chain return <code>NEUTRAL</code>, the value is considered valid. If any rule returns <code>DENY</code> or <code>ACCEPT</code>, that is the answer used and no further processing is done. Among other things, this allows for the creation of OR logic in your validator chain.</p>

    <p>For example, a common validator chain for Subversion commit messages might require you to reference a bug number or enter the string 'InternalFix' for changes with no bug. You would implement the validator chain like so:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $validator = new Zend_Validator($post);

    // Returns ACCEPT if the 'InternalFix' string is present, NEUTRAL otherwise
    $validator->addRule("msg", new My_Rule_SVN_Internal());

    // Both return NEUTRAL if valid, DENY if not
    $validator->addRule("msg", new My_Rule_SVN_ContainsBug(), "No bug number was found");
    $validator->addRule("msg", new My_Rule_SVN_BugsNumbersGood(), "An invalid bug number was entered");

    // Each field has its own validator chain.
    $validator->addRule("email", new Zend_Rule_Email(), "Not a valid email address");

    // Zend_Validator always returns a boolean answer.
    if ($validator->isValid()) {
    echo "VALID</br>";
    } else {
    echo "NOT VALID</br>";
    }
    ]]></ac:plain-text-body></ac:macro>

    <p>(In practice <code>My_Rule_SVN_ContainsBug</code> would probably validate the bug numbers too; I separated them for the example.)</p>

    <p>Another example:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    // Returns DENY if it's a knock-knock joke, NEUTRAL otherwise.
    $validator->addRule("joke", new Joke_Rule_KnockKnock(), "Please, no more knock-knock jokes");

    // Returns ALLOW for any blonde joke, NEUTRAL otherwise.
    $validator->addRule("joke", new Joke_Rule_Blonde());

    // All others must have a punchline, and I must get it.
    $validator->addRule("joke", new Joke_Rule_HasPunchline(), "There's no punchline");
    $validator->addRule("joke", new Joke_Rule_IGetIt(), "I don't get it");
    ]]></ac:plain-text-body></ac:macro>

    1. Jun 30, 2006

      <p>This is an interesting idea. The sense I get is that you want to add a way for a Rule to stop processing the chain and force a result. That is probably only needed for isValid==TRUE because once an error is returned by a Rule the Validator will return not valid. </p>

      1. Jun 30, 2006

        <p>Yes, but not for the entire validator, just the chain for one field. In other words, every field would be processed independently. A rule in the chain for a field could return a result that indicates the other rules for that field need not be consulted, but all of the other fields would always be evaluated. If all rules return <code>NEUTRAL</code> or <code>ALLOW</code>, the validator returns <code>true</code>. If any rule for any field returns <code>DENY</code>, the validator returns <code>false</code> and <code>getErrorList()</code> returns all of the failure messages.</p>

        1. Jun 30, 2006

          <p>Sorry, yes I agree completely. I was thinking of the ability to stop processing for the chain of an individual field. The think I am not clear about is the implementation. Is it NEUTRAL/ALLOW/DENY or is it INVALID/VALID/INVALID_STOP_PROCESSING_RULES ? The latter makes more sense to me, but it may not be exactly what you have in mind. </p>

          1. Jun 30, 2006

            <p><code>ALLOW</code> would cause further processing to stop as well. Maybe the call in Zend_Rule should be "<code>decide($value)</code>" instead of "<code>validate($value)</code>", which would make the constant names clearer.</p>

            <p>In essence, what I'm describing is that instead of a binary <code>VALID</code>/<code>INVALID</code> response, there are three potential responses:</p>

            <ul>
            <li>Authoritative "yes". Final answer; no other rules need be consulted. (<code>ALLOW</code>)</li>
            </ul>

            <ul>
            <li>Authoritative "no". Final answer; no other rules need be consulted. (<code>DENY</code>)</li>
            </ul>

            <ul>
            <li>No decision. Assume "yes" unless another rule says "no". (<code>NEUTRAL</code>)</li>
            </ul>

            <p>With this configuration, there are two <code>VALID</code> responses. The first, <code>ALLOW</code>, is an instant positive, and no other rules in the chain – even if they would have responded negatively – are consulted. This allows you to handle the exception cases.</p>

            <p>The second, <code>NEUTRAL</code>, is passive. It relies on the responses of the other rules to make the final decision. If all others return <code>NEUTRAL</code>, the result is positive. If any other returns <code>DENY</code>, the result is negative.</p>

            <p>Here's another example: a date field is optional, so must either be empty or contain a valid date some time in the future. There are three rules. The first allows empty values, the second validates the date string, and the third checks the range.</p>

            <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
            // Returns ALLOW if blank; no further processing is done, NEUTRAL otherwise.
            $validator->addRule("date", new Zend_Rule_AllowBlank());

            // Real syntactical checks. Both return DENY on failure, NEUTRAL otherwise.
            // Both rules would have returned DENY if the value was blank.
            $validator->addRule("date", new Zend_Rule_ValidDate());
            $validator->addRule("date", new Zend_Rule_DateRange("tomorrow", null));
            ]]></ac:plain-text-body></ac:macro>

            1. Jun 30, 2006

              <p>I am trying to map your three onto the current two to find what the new state is. I sounds like I had the stop processing the on the wrong one. </p>

              <ul class="alternate">
              <li>Authoritative "yes". Final answer; no other rules need be consulted. (ALLOW)<br />
              I believe this is the new state and I had it wrong above. It should be return no error and stor processing rules for this field. </li>
              </ul>

              <ul class="alternate">
              <li>Authoritative "no". Final answer; no other rules need be consulted. (DENY)<br />
              This is the same as any Rule returning any error. The difference is that all rules are normally processed. </li>
              </ul>

              <ul class="alternate">
              <li>No decision. Assume "yes" unless another rule says "no". (NEUTRAL)<br />
              This is he same as a Rule not returning an error.</li>
              </ul>

              <p>However for special cases like you are describing you could also combine a check of isValid() and inspecting the specific errors that are returned. The goal of the Validator is to gather all the error messages from all the rules that failed. The isValid() and isError() methods are based on any error. But you can always inspect the error array returned and make a more specific logic or only use some values.</p>

              <p>The thing I don't know is if this would be a commonly used addition or a rare thing that there is an alternate solution for. </p>

              1. Jul 14, 2006

                <p><em>My most recent response on the mailing list a couple of weeks ago:</em></p>

                <p>This mapping is pretty much right. Depending on the complexity of the validator, it may still be desirable to prevent further rule processing on a DENY because you have other ALLOW rules further down the chain that must not be evaluated:</p>

                <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
                $validator->addRule("field", new Zend_Rule_NotBlank());
                $validator->addRule("field", new Zend_Rule_IsNumeric());

                // DENY all compromised numbers
                $validator->addRule("field", new My_Rule_BannedNumber());

                // ALLOW any with the magic prefix
                $validator->addRule("field", new My_Rule_HasMagicPrefix());

                $validator->addRule("field", new My_Rule_SomethingElse());
                $validator->addRule("field", new My_Rule_SomethingElse());
                ...
                ]]></ac:plain-text-body></ac:macro>

                <p>This isn't the best example, but I'm struggling to come up with a better one off the top of my head. I hope this conveys the idea.</p>

                <p>How about a fourth answer, <code>FAIL</code>, for normal validation errors:</p>

                <ul>
                <li><code>ALLOW</code>: Authoritative "yes". Stop validating this field.</li>
                <li><code>DENY</code>: Authoritative "no". Stop validating this field.</li>
                <li><code>FAIL</code>: Rule failed. Record the error and continue validating this field.</li>
                <li><code>NEUTRAL</code> (or maybe <code>PASS</code>): Rule passed. Continue validating this field.</li>
                </ul>

                <blockquote><p>...But you can always inspect the error array returned and make a more specific logic or only use some values.</p></blockquote>

                <p>I always cringe any time I think about string parsing of error messages. They're just too brittle; they frequently evolve over the course of development and in response to tech support feedback. And once you start talking i18n, parsing of error messages begins to fail quite spectacularly. This is why I always use a code when throwing exceptions.</p>

                <blockquote><p>The thing I don't know is if this would be a commonly used addition or a rare thing that there is an alternate solution for.</p></blockquote>

                <p>The only examples I can come up with right now are for HTML form validation. However, <code>Zend_Validate</code>, as a general-purpose class, could be used to construct very complex validation rules for other things, such as DB query results or even application business logic decisions. For many of these applications, simple "all pass" or "all fail" logic may not be sufficient.</p>

  5. Jul 14, 2006

    <p>My votes as well - with the cascading ruleset as suggested by Willie and customisable error responses.</p>

  6. Aug 06, 2006

    <p>What about default values if filter/validate doesn't pass the rule?</p>

    <p>$validator->addRule("carType", new Zend_Rule_IsOneOf($ArrayOfCarTypes), 'private');</p>

  7. Aug 28, 2006

    <p>1. Is it possible to specify that a filter should be applied to all inputs without naming each input individually? For example, I may always want to apply strip_tags() to all inputs.</p>

    <p>2. Can we assume that arrays in the input would be detected and the filter/validation be applied to each individual element of the array? Need to think about error messages for arrays.</p>

    <p>3. Would it make sense to treat a FilterChain as a container and to be able to pass it to the validator? When the validator requests an input from the filter chain the filter chain would then apply the filter and return the result. The original $post data would remain unchanged.<br />
    $filterChain = new FilterChain(); // and add filers<br />
    $validator = new Validator($filterChain);</p>

    <p>4. Think we need to carefully consider the overall naming scheme for the classes so everything makes sense from a big picture point of view. Need to tie the Request class, the possible Form classes along with these classes together without coupling them too closely.</p>

    <p>5. Might consider a helper class approach. <br />
    $filter->addFilter('field1', new Zend_Filter_Int());<br />
    could be:<br />
    $filter->addFilter('field1', 'int');<br />
    So folks could override a filter without changing the class name in their code.</p>

    <p>6. Consider having addFilters() and addRules() so we can pass an array of filters/rules. Maybe have the constructor accept an array as well.</p>

  8. Sep 26, 2006

    <p>Hi,</p>

    <p>since the Zend_Form proposal (which is currently reworked) will have some dependencies with Zend_FilterChain and Zend_Validator, may I ask about the current status of this proposal? I am just asking because it hasn't been changed and commented in a while. </p>

    <p>Anyway, should Zend_FilterChain not rather be called Zend_Filter_Chain?</p>

    <p>Another question, which project team will be responsible for Zend_Filter_Chain and Zend_Validator?</p>

    <p>Thanks for any feedback.</p>

    <p>Best Regards,</p>

    <p>Ralf</p>

  9. Oct 14, 2006

    <p>Hi again,</p>

    <p>since I started working with Zend_Filter and I am really waiting for Zend_FilterChain I have some more thoughts for this proposal. They are not sorted but I just want to through them in.</p>

    <p>a) If the filter rules get there own classes (e.g. Zend_Filter_Int, Zend_Filter_Range, etc.) will we really need the current Zend_Filter class with its static methods any more? Would it make sense to anyone else than me that the Zend_FilterChain could be the new Zend_Filter doclass? </p>

    <p>b) I am still not completely satisfied with the class namings. Zend_Validator is a container for Zend_Rule_* objects and Zend_FilterChain is a container for Zend_Filter_* objects. So in my opinion the use cases should look like this:</p>

    <p>Zend_Filter:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $filter = new Zend_Filter($post);
    $filter->addFilter('field1', new Zend_Filter_Int());
    $filter->addFilter('field1', new Zend_Filter_Range(1, 100));
    $filter->addFilter('field2', new Zend_Filter_Alpha());
    $filter->addFilter('field3', new Zend_Filter_Regexp('/[^a-zA-Z0-9\@\.\-\_]/', ''));
    $filter->doFilter();
    ]]></ac:plain-text-body></ac:macro>

    <p>Zend_Validator:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $validator = new Zend_Validator($post);
    $validator->addRule('field1', new Zend_Validator_IsNull(), 'please enter field1');
    $validator->addRule('field1', new Zend_Validator_Int(), 'not an integer');
    $validator->addRule('field2', new Zend_Validator_IsNull(), 'please enter an email address');
    $validator->addRule('field2', new Zend_Validator_Email(), 'not a valid email address');
    $validator->addRule('field3', new Zend_Validator_Range(10, 20), 'number not in range 10-20');
    if ($validator->isValid()) {
    echo 'VALID</br>';
    } else {
    echo 'NOT VALID</br>';
    }
    ]]></ac:plain-text-body></ac:macro>

    <p>With this class renaming the usage of Zend_Filter and Zend_Validator becomes more consistent. </p>

    <p>c) Regarding the former usage of Zend_Filter this could be changed like this.</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    // old usage
    Zend_Filter::getAlpha($value);

    // new usage
    Zend_Filter_Alpha::doFilter($value);
    ]]></ac:plain-text-body></ac:macro>

    <p>I am not quite sure if it is practical to have a method that can be called both static and from an instance. If not, maybe we add a static method filter() and the instance method doFilter() calls this static method?</p>

    <p>d) Of course these changes will need some reworking of Zend_Filter_Input but I guess it is worth it.</p>

    <p>e) And another thought: Maybe it would make more sense to call the rules classes like this:</p>

    <p>Zend_Filter_Alpha => Zend_Filter_Rule_Alpha<br />
    Zend_Filter_Int => Zend_Filter_Rule_Int</p>

    <p>This prevents name clashes between Zend_Filter_Input and the Zend_Filter_* rules. The same will apply to the Zend_Validator_* rules. </p>

    <p>f) And here is my last thought: maybe we could even combine the Zend_Filter_Rule_* classes and the Zend_Validator_Rule_* classes to a bunch of Zend_Rule_* classes which can both do the filtering and the validating?</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    // use for filtering
    Zend_Rule_Alpha::doFilter();

    // use for validating
    Zend_Rule_Alpha::isValid();
    ]]></ac:plain-text-body></ac:macro>

    <p>Ok, that was it for now. Are these suggestion all just mad or do they make sense to anyone?</p>

    <p>Best Regards,</p>

    <p>Ralf</p>

    1. Oct 15, 2006

      <p>I am very much in favor of your proposal.</p>

      <p>By giving each Filter or Validation rule its own class, you make the ruleset extensible. The only thing you would need is some interface for the filters. I forsee only one method for this interface:</p>
      <ac:macro ac:name="noformat"><ac:plain-text-body><![CDATA[
      public function isValid($value) // should return either true of false
      ]]></ac:plain-text-body></ac:macro>
      <p>About your point c), I don't think it is a good idea to make the methods available statically. In some filters or validation rules, you need some extra parameters (e.g. a regular expression, or min-max combination), which in your examples (at point b)), are passed as constructor arguments.</p>

      <p>However, I would have expected a validation called "Zend_Validator_IsNull" to pass, when the given argument is null. In your example, you'd probably want to name the class "Zend_Validator_NotNull" or "Zend_Validator_Required".</p>

      <p> I hope my comments are of any value.</p>

      <p>Regards,</p>

      <p> Allard</p>

      <p>---- PS. please forgive me if I've used the wrong wiki tags. I'm not very familiar with it yet.</p>

  10. Oct 16, 2006

    <p>I'd like to propose a validator that can validate across multiple fields. For example, take the case of a user registration form with optional address fields. For a valid address, the user must fill out the address, city, state, and zip. Partially filling out the address should result in an error. So in this case we would have:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $us_states = array("TX"=>"Texas",...); $validator = new Zend_Validator($post);$validator->addRule('city', new Zend_Validator_Alpha());$validator->addRule('state', new Zend_Validator_Enum(array_keys($us_states)));$validator->addRule('zipcode', new Zend_Validator_Zipcode()); // Multi-field validation $validator->addRule(null, new Zend_Validator_Allornone('address1', 'city', 'state', 'zipcode'));
    ]]></ac:plain-text-body></ac:macro>

    <p>This could also be used in the case of a login form. Zend_Validator_Login('username', 'password').</p>

  11. Oct 16, 2006

    <p>I suggest including some practical, real-world examples in the use cases, including all code neeeded from the developer's perspective. For example, consider a standard web contact form with, sender, subject, email, URL, message, city, region, postal code, country, and maybe a couple more fields like "how would you rate ... ?", "how did you find our website?", and "tell a friend" (another email address). I think if we look at all the userland code needed for a robust, practical example, then it will be easier to identify what is practical, needed, or not needed.</p>

    1. Oct 17, 2006

      <p>Do not forget that people (especially developers) will always find themselves in a situation that hadn't been forseen.</p>

      <p>I think the most important thing to do is make the validation component extensible. There should, IMHO, be an interface to define what validation rules look like. That way, any developer can create additional rules, no matter how complex they are.</p>

      <p>Even Dale M.'s idea of multi-field validation (good idea!!) could be made possible by creating an additional rule class. YOu could think of rules like Dale's "AllOrNone", of AtLeastOneOf, and AtMostOneOf.</p>

      1. Oct 26, 2006

        <p>Extensibility and flexibility are worthy goals, but we must first demonstrate proposed solutions provide simple, easy-to-use, intuitive solutions for the common cases most developers must solve.</p>

  12. Dec 07, 2006

    <p>I suggest that the getError method should return an empty string instead of null. It should also allows HTML wraps around the error message:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    /*

    • Inside Zend_View
    • Assumming validator is passed to Zend_View as a reference
      */

    /*

    • You must check for whether or not an error exists for each field in Zend_View
    • This is really ugly inside views when you have to do it for a lot of fields
      */
      if($error = $this->validator->getError('username'))
      {
      echo '<span class="error">' . $this->escape( $error ) . '</span>';
      }

    /*

    • Suggested alternative,
    • Inside Zend_Validator:
      */
      public function getError($key = null, $htmlWrap = '?')
      {
      // ...

    // if error exists:
    return str_replace('?', $errorMsg, $htmlWrap);

    // else:
    return '';
    }

    /*

    • As a result, we no longer need to check on whether or not there is an
    • error associated with a field, we simply print it
      */
      echo $this->escape($this->validator->getError('username');
      ]]></ac:plain-text-body></ac:macro>
    1. Dec 07, 2006

      <p>I'm sorry, in the code above, the last statement should be:</p>

      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      echo $this->escape($this->validator->getError('username', '<span class="error">?</span>');
      ]]></ac:plain-text-body></ac:macro>

  13. Feb 02, 2007

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Comments</ac:parameter><ac:rich-text-body>
    <p>Except for directly supporting dictionary arrays (i.e., not multidimensional arrays) of input, the requirements of this proposal are reasonably met with approved functionality from the <a href="http://framework.zend.com/wiki/x/Wi8">Zend_Filter Design Proposal</a>, which is largely based on ideas illustrated by this proposal.</p></ac:rich-text-body></ac:macro>