ZF-4319: solution for Transfer-Adapter's file-hashmap structure defect, supporting subforms
Description
The problem which causes file upload to fail is about the internal key naming of upload files. For subforms files are mapped to a key-array-pair rather than a key-string-pair. So no string hashmap is built internal.
For me following fix works fine. I've tested with nested subform depths 0 to 3.
Testcode:
// Creating form
$form = new Zend_Form();
$form->setEnctype('multipart/form-data');
// File Upload Element
$element = new Zend_Form_Element_File('file1', array('label' => 'Datei'));
$element->setRequired(TRUE);
// Test1: no subform
$form->addElement($element);
// Test2: simple subform
//$subformFile = new Zend_Form_SubForm();
//$subformFile->addElement($element);
//$form->addSubform($subformFile, 'subformFile');
// Test3: one nested subform
//$subformFile = new Zend_Form_SubForm();
//$subformFile->addElement($element);
//$subform1 = new Zend_Form_SubForm();
//$subform1->addSubform($subformFile, 'subformFile');
//$form->addSubform($subform1, 'subform1');
// Test4: doublenested subform
//$subformFile = new Zend_Form_SubForm();
//$subformFile->addElement($element);
//$subform1 = new Zend_Form_SubForm();
//$subform1->addSubform($subformFile, 'subformFile');
//$subform2 = new Zend_Form_SubForm();
//$subform2->addSubform($subform1, 'subform1');
//$form->addSubform($subform2, 'subform2');
// Test5: triplenested subform
//$subformFile = new Zend_Form_SubForm();
//$subformFile->addElement($element);
//$subform1 = new Zend_Form_SubForm();
//$subform1->addSubform($subformFile, 'subformFile');
//$subform2 = new Zend_Form_SubForm();
//$subform2->addSubform($subform1, 'subform1');
//$subform3 = new Zend_Form_SubForm();
//$subform3->addSubform($subform2, 'subform2');
//$form->addSubform($subform3, 'subform3');
Fix in Zend_File_Transfer_Adapter_Http:
/**
* Building file key an returns value, includes nested subform support.
*
* Example:
* The given key looks like this:
* 'subform3__subform2'
*
* The given array looks like this:
* array(1) {
* ["subform1"]=>
* array(1) {
* ["subformFile"]=>
* array(1) {
* ["file1"]=>
* string(0) "/uploaded/file.ext"
* }
* }
* }
*
* The returned key would be:
* 'subform3__subform2__subform1__subformFile__file1'
*
* The returned value would be: '/uploaded/file.ext'
*
* @param array $fileKeyValue
* @param string $key Return key
* @return string Value
*/
protected function _getFileKeyValue(array $fileKeyValue, &$key) {
list($keyAppend, $innerFileKeyValue) = each($fileKeyValue);
$key .= '__'.$keyAppend;
if (is_array($innerFileKeyValue)) {
$innerFileKeyValue = $this->_getFileKeyValue($innerFileKeyValue, $key);
}
return $innerFileKeyValue;
}
/**
* Prepare the $_FILES array to match the internal syntax of one file per entry
*
* @param array $files
* @return array
*/
protected function _prepareFiles(array $files = array())
{
$result = array();
foreach ($files as $form => $content) {
if (is_array($content['name'])) {
foreach ($content as $param => $file) {
$key = $form;
$value = $this->_getFileKeyValue($content[$param], $key);
$result[$key][$param] = $value;
}
} else {
$result[$form] = $content;
}
}
return $result;
}
=====================================================================================================
Damned, i didn't look to multiple files. Sorry.
I don't know why, but i don't have rights to comment any issues here, so let me append my answer. Hope it helps.
Testcode (not patched, just ZF 1.6.0):
// Creating form
$form = new Zend_Form();
$form->setEnctype('multipart/form-data');
// 2 File Upload Elements
$element = new Zend_Form_Element_File('file1', array('label' => 'Datei'));
$element->setRequired(TRUE);
$element2 = new Zend_Form_Element_File('file2', array('label' => 'Datei2'));
$element2->setRequired(TRUE);
// triplenested subform - 2 elements
$subformFile = new Zend_Form_SubForm();
$subformFile->addElement($element);
$subformFile->addElement($element2);
$subform1 = new Zend_Form_SubForm();
$subform1->addSubform($subformFile, 'subformFile');
$subform2 = new Zend_Form_SubForm();
$subform2->addSubform($subform1, 'subform1');
$subform3 = new Zend_Form_SubForm();
$subform3->addSubform($subform2, 'subform2');
$form->addSubform($subform3, 'subform3');
var_dump($_FILES);
var_dump($element->getFullyQualifiedName());
var_dump($element->getId());
var_dump($element2->getFullyQualifiedName());
var_dump($element2->getId());
var_dump($subformFile->getFullyQualifiedName());
var_dump($subformFile->getId());
var_dump($subform1->getFullyQualifiedName());
var_dump($subform1->getId());
var_dump($subform2->getFullyQualifiedName());
var_dump($subform2->getId());
var_dump($subform3->getFullyQualifiedName());
var_dump($subform3->getId());
var_dump($form->getFullyQualifiedName());
var_dump($form->getId());
dump:
array(1) {
["subform3"]=>
array(5) {
["name"]=>
array(1) {
["subform2"]=>
array(1) {
["subform1"]=>
array(1) {
["subformFile"]=>
array(2) {
["file1"]=>
string(0) ""
["file2"]=>
string(0) ""
}
}
}
}
["type"]=>
array(1) {
["subform2"]=>
array(1) {
["subform1"]=>
array(1) {
["subformFile"]=>
array(2) {
["file1"]=>
string(0) ""
["file2"]=>
string(0) ""
}
}
}
}
["tmp_name"]=>
array(1) {
["subform2"]=>
array(1) {
["subform1"]=>
array(1) {
["subformFile"]=>
array(2) {
["file1"]=>
string(0) ""
["file2"]=>
string(0) ""
}
}
}
}
["error"]=>
array(1) {
["subform2"]=>
array(1) {
["subform1"]=>
array(1) {
["subformFile"]=>
array(2) {
["file1"]=>
int(4)
["file2"]=>
int(4)
}
}
}
}
["size"]=>
array(1) {
["subform2"]=>
array(1) {
["subform1"]=>
array(1) {
["subformFile"]=>
array(2) {
["file1"]=>
int(0)
["file2"]=>
int(0)
}
}
}
}
}
}
string(5) "file1"
string(5) "file1"
string(5) "file2"
string(5) "file2"
string(11) "subformFile"
string(11) "subformFile"
string(8) "subform1"
string(8) "subform1"
string(8) "subform2"
string(8) "subform2"
string(8) "subform3"
string(8) "subform3"
NULL
NULL
Comments
Posted by Thomas Weidner (thomas) on 2008-09-17T22:33:29.000+0000
I'm sorry, but this is not a proper solution. Set 2 file elements in every form/subform and you will see why your solution does not work.
But you can help me out: Can you give me your $_FILES array using this 3-nested form (with 2 file elements) ? Also the value of getFullyQualifiedName() and getId() would be interesting. And when you set a different name and a different id in the form.
The solution I have worked out will be available in a few days because we always need unittests and documentation before doing a commit.
Posted by Thomas Weidner (thomas) on 2008-09-25T10:33:51.000+0000
This solution does not work. A working solution has been added with r11518
Posted by Wil Sinclair (wil) on 2008-11-13T14:10:28.000+0000
Changing issues in preparation for the 1.7.0 release.