Thursday
25
September
2008

Subforms and multiple file elements

Hy interested ones,

when you are using Zend_Form for your file upload I have new informations for you.

*) Subforms
Using file elements in sub forms was not possible in the past. The reason was that sub forms are created by using multidimensional names, but in HTML multidimensional names are not supported for file elements.

Now this is possible. I have added a new decorator with the help of Matthew which is automatically be used for file elements. It changes the elements name in a way which is supported by HTML.

As you can see in the following example, even multi-nested subforms are supported.

$form = new Zend_Form();
$form->setEnctype('multipart/form-data');
$form->setAction('index2.php');
	
// Button
$button = new Zend_Form_Element_Submit('submit');
$form->addElement($button);
	
// File Upload Elements
$element = new Zend_Form_Element_File('firstfile');
$element2 = new Zend_Form_Element_File('secondfile');
	
// 3-Level subform
$subform0 = new Zend_Form_SubForm();
$subform0->addElement($element);
$subform0->addElement($element2);
$subform1 = new Zend_Form_SubForm();
$subform1->addSubform($subform0, 'subform0');
$subform2 = new Zend_Form_SubForm();
$subform2->addSubform($subform1, 'subform1');
$subform3 = new Zend_Form_SubForm();
$subform3->addSubform($subform2, 'subform2');
$form->addSubform($subform3, 'subform3');
	
$form->setView(new Zend_View());
echo $form;

But note that the name of the file elements you set in a form and all it’s subforms must be unique. File elements with the same name are displayed but not submitted by your form.

*) Multiple file elements

Sometimes it is usefull to have multiple file elements which uses the same settings and validators. Writing plain HTML you would simply set a name like filename[] several times. Zend_Form_Element_File can handle this for you much simpler. Just create your element like before and call setMultiFile() with the number of files you want to have.

$element = new Zend_Form_Element_File("uploaded");
$element->setMultiFile(3);

The above example will create 3 seperated file elements named uploaded[].

I hope you find these two features handy.
New things will come soon.

Greetings
Thomas, I18N Team Leader, Zend Framework

Back to top
  1. fte

    Friday, September 26, 2008 - 16:56:27

    Thank you Thomas, it will be easier to make a mass grid edit with one subform by tr line !

  2. meuledor

    Friday, September 26, 2008 - 20:06:58

    Thanks Thomas, but how we can retrieve the files in the action_controller without using the $_FILES ?

  3. thomasw

    Friday, September 26, 2008 - 20:09:58

    As before by simply using Zend_File_Transfer direct

  4. Angie Cudris

    Friday, November 28, 2008 - 00:03:09

    How can i change the name of each file uploaded?

  5. thomasw

    Friday, November 28, 2008 - 00:21:43

    Why don’t you use the Rename Filter as described in the manual ?

  6. Flash

    Monday, February 9, 2009 - 19:13:08

    What a very cool blog! I just want you to know that I really appreciate what you have done.

  7. stefan schmidt

    Wednesday, February 11, 2009 - 18:43:23

    I think the question for renaming is still open: How can I rename multiple files? So e.g. $form->file1 has 2 or more files in, they are well uploaded - but no possibility to rename them whith the Rename-Filter?

  8. thomasw

    Wednesday, February 11, 2009 - 22:02:50

    No there is no open question.

    Actually the rename filter accepts only directories and does not provide regex filtering options. So renaming multiple files is possible but only resticted for now.

    A now not finished new feature is not a bug. ;-)

  9. Surt

    Thursday, April 16, 2009 - 14:49:35

    Hi, i can’t understand yet the example:

    if i set a form with subforms and them i add for each subform an element file (the same element) file names are not changing, so, how can i do this:

    inside Zend_Form instance:

    $media = new Zend_Form_Element_File(’media’);

    $sub1 = new Product_Forms_Submedia();
    $sub1->addElement($media);
    $this->addSubForm($sub1, ‘1′);

    $sub2 = new Product_Forms_Submedia();
    $sub2->addElement($media);
    $this->addSubForm($sub2, ‘2′);

    My file elements inside the forms appears with the same name…
    i tried to setOptions and getOptions inside the init method on the subform, to set the file element name different, but there is no getOptions in subforms…
    I can’t find a way to do it, any clue?

  10. thomasw

    Thursday, April 16, 2009 - 15:36:00

    You are using the same file element with the same name multiple times… and I wrote in my blog:
    “But note that the name of the file elements you set in a form and all it’s subforms must be unique. File elements with the same name are displayed but not submitted by your form.”

    Both of your file elements are named “media”. So they don’t work as only one is submitted.

    You must set another name to the other element. Please look into the manual for how to archive this within Zend_Form.

  11. Adam Sowinski

    Monday, August 31, 2009 - 23:36:20

    I have set up 4 Zend_Form_Element_File elements:

    $file = new Zend_Form_Element_File(’file’);
    $file->setDestination(’/images/tmp’)
    ->setMultiFile(4)
    ->addValidator(’Size’, false, 30720)
    ->addValidator(’Extension’, false, ‘png,gif,txt,mov’);

    When I have for example 2 files to upload and they are with pdf extension I get only one validation error and not two. Is this normal behavior?

  12. Hanny

    Monday, July 18, 2011 - 15:06:00

    Hello Thomas,

    I hope you can help me on this one. I have searched for information to help me solve my problem but it seems the reason leading to errors is unique because I am not using caching or javascript frameworks, or any javascript for my forms. Not yet until everything is working fine in PHP.

    I wish I could indent my code in this form for better clarity.

    I am having problems validating a form with a file element in my application.

    I am building an application that requires that I show 2 subforms. The first sub form is always
    the same and the second subform shown will depend on the drop-down list of categories and subcategories selected in the
    first subform.

    My form class contains this category subform(the first sub form) and about 8 other subforms (one of which will be
    displayed depending on the information given in the first sub form). The reason is that the data I am collecting
    is different for a lot of the categories. Some are however the same so the 8 subforms include a more generic one
    which is the parent class. This is also reflected in the database table structure. I have been able to get all
    the logic for in my code for displaying the relevant sub form. Each second sub form includes a file element for
    uploading pictures.

    My controller class ProductController has the addAction that displays the initial subform through a function
    I call getFirstSubform.
    The post request from the first subform goes to a processAction which decides which sub form
    to desplay as the second. The second and final subform also makes a trip to the same processAction of the
    same controller. So the processAction has a logic to distinguish between these two POST request and to obtain the
    appropriate post data. In the fist subform request, I save these post data as session variables for later
    retrieval when saving to the database since these variables will be lost when making another browser request.
    After running the function getNextSubForm() to return an instance of the relevant second subform. I have given an
    explanatory code so you know what I am trying to do. During debugging I had the following observations.

    1. The form validates correctly when I do not add the file element for the pictures. When the file element is added it fails validation. I have set it to just a single file upload though when I sort out the problem. I will use setMultiFile(6) to set it to 6 files per adding product.

    2. When I include validators for the file elemement like addValidator(’Count’, false, array(’min’ => 0, ‘max’ => 6)),
    addValidator(’Size’ false, ‘4MB’), addValidator(’Extension’, false, array(’jpg’, ‘jpeg’, ‘png’, ‘gif’)), I don’t
    get any error message on form but it still fails validation and the form is repopulated.

    3. When I do not include these validators, I get the error message: File ‘pictures’ exceeds the defined ini size.
    I have made sure my second subform is set to enctype=”multipart/form-data”. I even explicitly set my first subform
    to this enctype during debugging just in case this was causing the error.
    In my PHP.ini file I have set post_max_size = 500M, upload_max_filesize = 500M, just to be sure this is not what
    is causing the error.

    4. After retrieving $form form session in processAction, when I do $form->removeElement(’pictures’) just before
    the validation block, the validation works.

    5. When I upload a file. ‘error’ is set to int(0). When I don’t upload anything it’s set to int(4). I don’t find any
    file in default temp folder C:wamptmp after submiting the last form but will see the tempfile for a moment then it
    it will quickly vanish. I can’t see it in the folder I set if I include the method setDestination() on the file
    element.

    array
    ‘pictures’ =>
    array
    ‘name’ => string ‘this.jpg’
    ‘type’ => string ‘image/jpeg’
    ‘tmp_name => ‘C:wamptmpphp93D.tmp’
    ‘error’ => int 0
    ’size’ => int 178993

    Note: I am NOT using ajax, jQuery, or javascript on this subform at the moment. Only using Zend_Form_whatever.
    I am using Zend Framework 1.11.9. with WAMP

    Can you please help. I have been scratching my head on this for days.

    <?php
    class ProductController {

    public function getFirstSubForm() {
    //logic for displaying first subform
    }
    public function getNextSubForm() {
    //logic for displaying next subform based on data from first subform
    //also save data from first subform in session for later retrieval
    }

    … etc
    public funtion addAction() {
    // Do some things and display first subform
    // action of first subform goes to processAction
    //getFirstSubform called here
    }

    public function processAction() {
    if (post data is comming from first subform) {
    //do something here and display relevant second subform
    //also create and store first subform data in
    //getNextSubForm called here


    //then create session variable for subform and store form

    $productControllerForm->subform = $form;
    }
    else {
    //request coming from second subform
    $form_data = $request->getPost()
    $form = $SESSION[’productController’][’subform’];
    Zend_Debug::dump($_FILES);
    if ($form->isValid($form_data)) {
    // retrieve data from fist subform and save in variables
    foreach ($form_data as $key => $value) {
    //save post data into database tables depending on second subform displayed
    if ($key == ‘car’) {
    // I am always choosing same options from first sub form so that I always
    // get this sub form for debugging purposes.
    $title = $value[’title’];

    …etc.
    $uploaded_data = $form->getValues();
    // $fullFilePath = form->pictures->getValues()
    }
    elseif (…) {


    elseif (…) {


    }

    }
    $this->render(’confirmation’);
    exit;
    }
    else {
    $form->populate($form_data);
    }

    }
    }