ZF-4347: Problem with breakChainOnFailure in Zend_File_Transfer_Adapter_Abstract

Description

When using the breakChainOnFailure feature for file validators, the chain will break even if the validator does not return an error.

In the isValid() function in Zend_File_Transfer_Adapter_Abstract all validators will be run in a foreach loop. The check if breakChainOnFailure in


if ($this->_break[$class]) {
                        $break = true;
                        break;
}

will break the loop without a check if there were errors in the validator, then the remaining validators in the chain are skipped.

I fixed it with the following replacement code ( does not mean it is the right solution ):


if ($this->_break[$class] && count($validator->getMessages()) > 0) {
                        $break = true;
                        break;
}

Comments

This fix only works well if you have just 1 file element in the form.

The general problem with multiple file elements and breakChainOnFailure is that they all share the validators trough the adapter. Basically this is a good idea but leads to a problem.

When the first element in the form gets validated and an error was found, for example the file has a wrong extension, all following form elements having the same validator will skip all validators coming after this validator in the chain. This happens because the extension validator carries already a message from the first element.

So if you have an ImageSize validator later in the chain for all elements, it wont be checked because the foreach loop will be left because of the previous Extension validator.

Note: This wont be happen if each file element in the form has different validators.

There should be some reset function for the messages in the validators, so that the validation of each file element starts fresh and without any leftovers from previous file elements.

I forgot to mention that i am using latest trunk version.

You misunderstood the nature of breakChainOnFailure.

This work the same way like in Zend_Form. A element which breaks validation stops all further validations.

This is also true for file elements. As soon as a file element breaks validations the complete chain is stopped. Of course also for all further elements, because the whole validation stopped.

There is no way to have single elements be stopped and others after it be validated.

I experienced a different behavior of validation in Zend_Form. One invalid form element does not stop the whole validation process of the form. My impression is it that breakChainOnFailure just works locally for each form element, if they have multiple validators attached.

Thats why i was confused that file elements dont work the same way ( if there are multiple file elements in the form ).

I also noticed that the error messages for the file elements will just be returned from the Adapter. Thats ok if you have only one file element. With multiple file elements, the error messages from the adapter should be transfered to each file element to avoid mixups.

To fix this i added the following code to the isValid() function of Zend_Form_Element_File:


if($adapter->hasErrors()) {
    $this->addErrors($adapter->getMessages());
}

if($adapter->hasErrors()) { 
      $this->addErrors($adapter->getMessages());
 }

This also means the getMessages() function can be removed from Zend_Form_Element_File.

The actual implementation does not have this problem. Validation is always done for single elements.