Hello everybody!

Thanks for your reply!

I personally hope, that context support will be one of the changes included
in ZF2, but in the meantime i extended Zend_Validate. At least I want to
post my solution to this problem.

---------------------

To use Validators the same way as Zend_Form_Element I had to make two
changes. First, the validator chain can not handle empty values by default.
When NULL or an empty value is passed, Zend_Form_Element returns TRUE by
default, except the value is required.

A validator like the Zend_Validate_Date will always return FALSE, when any
other value then a valid date is passed. Zend_Validate does not provide a
solution for this scenario, so I had to implement it similar to
Zend_Form_Element.

class App_Validate extends Zend_Validate {

        /**
         * 'Allow empty' flag
         * @var bool
         */
        protected $_allowEmpty = true;
        
    /**
         * Set 'allow empty' flag
         *
         * When the allow empty flag is enabled and the required flag is false, 
the
         * element will validate with empty values.
         *
         * @param  bool $flag
         * @return App_Validate
         */
    public function setAllowEmpty($flag)
    {
        $this->_allowEmpty = (bool) $flag;
        return $this;
    }
        
        /**
         * Get 'allow empty' flag
         *
         * @return bool
         */
        public function getAllowEmpty()
        {
                return $this->_allowEmpty;
        }
        
   /**
         * Returns true if and only if $value passes all validations in the 
chain
         *
         * Validators are run in the order in which they were added to the chain
(FIFO).
         *
         * @param  mixed $value
         * @return boolean
         */
    public function isValid($value = NULL)
    {
        if ((('' === $value) || (NULL === $value))
                        && $this->getAllowEmpty()
                ) {
                        return TRUE;
                }
                
        return parent::isValid($value);
    }
        

    public function addValidator(Zend_Validate_Interface $validator,
$breakChainOnFailure = false)
    {
        if ($validator instanceof Zend_Validate_NotEmpty)
                $this->setAllowEmpty(FALSE);
        
        return parent::addValidator($validator, $breakChainOnFailure);
    }
        
}

The property "$_allowEmpty" is TRUE by default and the method
"addValidator()" looks for "Zend_Validate_NotEmpty" to see if a value is
required and calls the parent method. The "isValid()" method just checks for
empty values and - again - calls the parent method.

That schould do the trick for empty values.

The second problem - the reason for this post - are validators that need the
context param to function properly. Again, Zend_Validate does not deliver a
solution for this problem either so I had to implement it. It is fairly
simple, all I had to do is copy the "isValid()" method from Zend_Validate,
make the changes for empty values and pass the context.

    public function isValid($value = NULL, $context = NULL)
    {
        if ((('' === $value) || (null === $value))
                        && $this->getAllowEmpty()
                ) {
                        return true;
                }
                
        $this->_messages = array();
        $this->_errors   = array();
        $result = true;
        foreach ($this->_validators as $element) {
            $validator = $element['instance'];
            if ($validator->isValid($value, $context)) {
                continue;
            }
            $result = false;
            $messages = $validator->getMessages();
            $this->_messages = array_merge($this->_messages, $messages);
            $this->_errors   = array_merge($this->_errors,  
array_keys($messages));
            if ($element['breakChainOnFailure']) {
                break;
            }
        }
        return $result;
    }

At this point, the new App_Validate handles validators in many respects to
Zent_Form_Element:

<?php
        $validateChain = new App_Validate();
        $validateChain->addValidator(new Zend_Validate_Digits());
        $validateChain->addValidator(new Zend_Validate_GreaterThan(5));
        $validateChain->addValidator(new Zend_Validate_LessThan(10));
        /** try also with NotEmpty validator */
        //$validateChain->addValidator(new Zend_Validate_NotEmpty());
        
        /** using the validator chain to check the value */
        var_dump($validateChain->isValid(NULL, $context));
        var_dump($validateChain->isValid(3, $context));
        var_dump($validateChain->isValid('abc', $context));
        var_dump($validateChain->isValid(7, $context));
        
        /** using a Zend_Form_Element to check the value */
        $element = new Zend_Form_Element_Text('number');
        $element->addValidator($validatorChain);
        
        var_dump($element->isValid(NULL, $context));
        var_dump($element->isValid(3, $context));
        var_dump($element->isValid('abc', $context));
        var_dump($element->isValid(7, $context));

And in conclusion the full-featured class:

<?php

class App_Validate extends Zend_Validate {

        /**
         * 'Allow empty' flag
         * @var bool
         */
        protected $_allowEmpty = true;
        
    /**
         * Set 'allow empty' flag
         *
         * When the allow empty flag is enabled and the required flag is false, 
the
         * element will validate with empty values.
         *
         * @param  bool $flag
         * @return App_Validate
         */
    public function setAllowEmpty($flag)
    {
        $this->_allowEmpty = (bool) $flag;
        return $this;
    }
        
        /**
         * Get 'allow empty' flag
         *
         * @return bool
         */
        public function getAllowEmpty()
        {
                return $this->_allowEmpty;
        }
        
   /**
         * Returns true if and only if $value passes all validations in the 
chain
         *
         * Validators are run in the order in which they were added to the chain
(FIFO).
         *
         * @param  mixed $value
         * @return boolean
         */
    public function isValid($value = NULL, $context = NULL)
    {
        if ((('' === $value) || (null === $value))
                        && $this->getAllowEmpty()
                ) {
                        return true;
                }
                
        $this->_messages = array();
        $this->_errors   = array();
        $result = true;
        foreach ($this->_validators as $element) {
            $validator = $element['instance'];
            if ($validator->isValid($value, $context)) {
                continue;
            }
            $result = false;
            $messages = $validator->getMessages();
            $this->_messages = array_merge($this->_messages, $messages);
            $this->_errors   = array_merge($this->_errors,  
array_keys($messages));
            if ($element['breakChainOnFailure']) {
                break;
            }
        }
        return $result;
    }
        

    public function addValidator(Zend_Validate_Interface $validator,
$breakChainOnFailure = false)
    {
        if ($validator instanceof Zend_Validate_NotEmpty)
                $this->setAllowEmpty(FALSE);
        
        return parent::addValidator($validator, $breakChainOnFailure);
    }
        
}
-- 
View this message in context: 
http://zend-framework-community.634137.n4.nabble.com/validator-chains-and-context-tp2130875p2173617.html
Sent from the Zend Framework mailing list archive at Nabble.com.

Reply via email to