I'm using Zend_Validate_Db_NoRecordExists and I would like to validate my Zend_Form against two fields in DB, sample code:
$phone_1 = new Zend_Form_Element_Text('phone_1');
$phone_1->addValidator(new Zend_Validate_Db_NoRecordExists(
array(
'field' => 'phone_1',
'table' => 'customer',
)))
->addValidator(new Zend_Validate_Db_NoRecordExists(
array(
'field' => 'phone_2',
'table' => 'customer',
)));
Can I accomplish this?
$chain = new Zend_Validate();
$foo = new Zend_Validate_Db_NoRecordExists(...);
$bar = new Zend_Validate_Db_NoRecordExists(...);
$chain->addValidator($foo)
->addValidator($bar);
$element->addValidator($chain);
UPDATE @Bob Kruithof
Quick and dirty sample using ZF 1.12.3. All code samples and line numbers are from ZF 1.12.3
<?php
$aPaths = array(
'path/to/zf'
);
set_include_path(implode(PATH_SEPARATOR, $aPaths));
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$element = new Zend_Form_Element_Text('testSO');
$chain = new Zend_Validate();
$bar = new Zend_Validate_Regex('/^Test/');
$baz = new Zend_Validate_Regex('/Valid$/');
$chain->addValidator($bar)
->addValidator($baz);
$element->addValidator($chain);
echo PHP_VERSION . ', ' . Zend_Version::getLatest() . PHP_EOL;
var_dump($element->isValid('Test'));
var_dump($element->isValid('Valid'));
var_dump($element->isValid('Test Valid'));
/* output
5.3.8, 1.12.3
bool(false)
bool(false)
bool(true)
*/
?>
Why this works: Zend_Form_Element.php
lines 1144 - 1168 sets validators either by Zend_Validate
object or by string. You are right - if validators are used with name, not as chain, then as a result one would have single validator. But in result we have:
$this->_validators[$name] = $validator;
/* debugger info:
$name --> (string) Zend_Validate
$validator --> Zend_Validate object {
_validators => array(2) (
[0] => array(2) (
[instance] => Zend_Validate_Regex object {
}
[breakChainOnFailure] => (bool) false
)
[1] => array(2) (
[instance] => Zend_Validate_Regex object {
}
[breakChainOnFailure] => (bool) false
)
)
_messages => array(0)
_errors => array(0)
zfBreakChainOnFailure => (bool) false
}
*/
public function addValidator($validator, $breakChainOnFailure = false, $options = array())
{
if ($validator instanceof Zend_Validate_Interface) {
$name = get_class($validator);
if (!isset($validator->zfBreakChainOnFailure)) {
$validator->zfBreakChainOnFailure = $breakChainOnFailure;
}
} elseif (is_string($validator)) {
$name = $validator;
$validator = array(
'validator' => $validator,
'breakChainOnFailure' => $breakChainOnFailure,
'options' => $options,
);
} else {
require_once 'Zend/Form/Exception.php';
throw new Zend_Form_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface');
}
$this->_validators[$name] = $validator;
return $this;
}
When we call $element->isValid())
it iterates over all validators inside of the chain - check Zend_Validate.php
, lines 91-110:
public function isValid($value)
{
$this->_messages = array();
$this->_errors = array();
$result = true;
foreach ($this->_validators as $element) {
$validator = $element['instance'];
if ($validator->isValid($value)) {
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;
}
$this->_validators
is our array of validators:
array(2) (
[0] => array(2) (
[instance] => Zend_Validate_Regex object {
_messageTemplates => array(3) (
)
_messageVariables => array(1) (
)
_pattern => (string) /^Test/
_value => null
_messages => array(0)
_obscureValue => (bool) false
_errors => array(0)
_translator => null
_translatorDisabled => (bool) false
}
[breakChainOnFailure] => (bool) false
)
[1] => array(2) (
[instance] => Zend_Validate_Regex object...