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.