ZF-6904: Two Validators of the same class can not be used two times for a field in form to validate two values in db


Example: $validatorUniqueEmail = new Zend_Validate_Db_NoRecordExists('users', 'email'); $validatorUniqueEmailNew = new Zend_Validate_Db_NoRecordExists('users', 'newemail'); $email = new Zend_Form_Element_Text('email'); $email->setRequired(true) ->setLabel('E-Mail addresse) ->addValidator($validatorUniqueEmail) ->addValidator($validatorUniqueEmailNew); form->addElement($email);

Here we want to validate if the entered email is not stored in two fields of our db. The second validator overwrites the first validator in a strange unknown way. In this case only the second validator will work !!!

We had the bug in earlier releases of zend too and solved that issue with a copy of a our validators Example: $validatorUniqueEmail = new Extlib_Validate_DbUnique('users', 'email'); //$validatorUniqueEmailNew = new Extlib_Validate_DbUnique('users', 'newemail'); -> seems not to work! A ZEND BUG ? $validatorUniqueEmailNew = new Extlib_Validate_DbUniqueCopy('users', 'newemail'); -> works

Perhaps this helps to find the issue


Changing Component / Name.

This is not an issue with the Zend_Validate, but is an issue of Zend_Form_Element due to its internal naming of validators. (any two validators of the same name would produce the same result).

This issue probably cannot be resolved without breaking BC, and this use-case can be satisfied by using the exclude field of the DB validator. Unless further use-cases can be demonstrated that make this impracticable, I would suggest defering to 2.0

Suggesting close as 'Wont fix'

Noting Matthew's comments in ZF-4811, I've attached simple patch to fix this issue for the use case described (supplying element with validator objects).

It borrows from the alias system employed by element decorators, which allows you to have multiple instances of the same decorator by supplying an alias (see "Using Multiple Decorators of the Same Type -…).

Client code:

$element = new Zend_Form_Element_Text( 'foo' );
$validator1 = new Zend_Validate_InArray( array( 'a', 'b', 'c' ) );
$validator2 = new Zend_Validate_InArray( array( 'c', 'd', 'e' ) );
$element->addValidator( array( 'InArray1' => $validator1 ) );
$element->addValidator( array( 'InArray2' => $validator2 ) );
$element->setView( new Zend_View() );
var_dump( $element->isValid( 'c' ) );

To allow the passing of aliased validator class name (rather than actual instances), the lazy loader (_loadValidator) would also need to be modified in a similar fashion to _loadDecorator. The method signature would need to change in order to pass the alias, but this would not break BC.


Scrub previous comment, this use case can be achieved using validator chains.

$element = new Zend_Form_Element_Text( 'foo' );
$chain = new Zend_Validate();
$chain->addValidator( new Zend_Validate_InArray( array( 'a', 'b', 'c' ) ) )
      ->addValidator( new Zend_Validate_InArray( array( 'c', 'd', 'e' ) ) );
$element->addValidator( $chain );

Or in original example:

$validator = new Zend_Validate();
$validator->addValidator(new Zend_Validate_Db_NoRecordExists('users', 'email'));
          ->addValidator(new Zend_Validate_Db_NoRecordExists('users', 'newemail'));
$email = new Zend_Form_Element_Text('email');
      ->setLabel('E-Mail address')