phpfile-uploadcollectionszend-framework2post-redirect-get

FilePrg with collections on ZF2


I need to submit a form which contains some fields along with a collection of max 3 images using fileprg plugin for saving uploaded files in case there has been some validation errors.

I'd like not to switch to a different solution ( like splitting the form in subforms, or removing collection in favour of three different file fields ). The main problem I experience is that when the user submits an invalid file ( too big, or with invalid mimetype ) I'd like to report the error and allow to upload a different file. What happens instead is that the collection disappears from the form.

The same happens if the users submit no file at all, even if files are required. After testing with my own code, I decided to test on cgmartin code, and this happens anyway.

I know this could be banned like a duplicate of this question but I'm stuck in this problem by a couple of days.

This is my "fork" of cgmartin code ( I actually added the fileprg in the controller, view and form have been left untouched). Thanks. A.

public function collectionAction()
{
    $form = new Form\CollectionUpload('file-form');
    $prg = $this->fileprg($form);


    if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
        $this->getServiceLocator()->get('Zend/Log')->debug("Redirect to Get!");
        return $prg; // Return PRG redirect response
    } elseif (is_array($prg)) {


            if ($form->isValid()) {
                //
                // ...Save the form...
                //
                return $this->redirectToSuccessPage($form->getData());
            }

    }

    return array('form' => $form);
}

The view

<div>
 <a href="<?php echo $this->url('fileupload')?>">&laquo; Back to Examples Listing</a>
</div>

<h2><?php echo ($this->title) ?: 'File Upload Examples' ?></h2>

<?php
// Init Form
$form = $this->form;
$form->setAttribute('class', 'form-horizontal');
$form->prepare();

// Configure Errors Helper
$errorsHelper  = $this->plugin('formelementerrors');
$errorsHelper
    ->setMessageOpenFormat('<div class="help-block">')
    ->setMessageSeparatorString('</div><div class="help-block">')
    ->setMessageCloseString('</div>');
?>
<?php echo $this->form()->openTag($form); ?>
<fieldset>
    <legend><?php echo ($this->legend) ?: 'Multi-File Upload with Collections' ?></legend>

    <?php
    $elem = $form->get('text');
    $elem->setLabelAttributes(array('class' => 'control-label'));
    $errors = $elem->getMessages();
    $errorClass = (!empty($errors)) ? ' error' : '';
    ?>
    <div class="control-group<?php echo $errorClass ?>">
        <?php echo $this->formLabel($elem); ?>
        <div class="controls">
            <?php echo $this->formText($elem); ?>
            <?php echo $errorsHelper($elem); ?>
        </div>
    </div>

    <?php
    $collection = $form->get('file-collection');
    foreach ($collection as $elem) {
        $elem->setLabelAttributes(array('class' => 'control-label'));
        $errors = $elem->getMessages();
        $errorClass = (!empty($errors)) ? ' error' : '';
        ?>
        <div class="control-group<?php echo $errorClass ?>">
            <?php echo $this->formLabel($elem); ?>
            <div class="controls">
                <?php echo $this->formFile($elem); ?>
                <?php echo $errorsHelper($elem); ?>
            </div>
        </div>
        <?php
    }
    ?>
    <?php if (!empty($this->tempFiles)) { ?>
    <div class="control-group"><div class="controls">
        <div class="help-block">
            Uploaded: <ul>
            <?php foreach ($this->tempFiles as $tempFile) { ?>
            <li><?php echo $this->escapeHtml($tempFile['name']) ?></li>
            <?php } ?>
            </ul>
        </div>
    </div></div>
    <?php } ?>

    <div class="control-group">
        <div class="controls">
            <button class="btn btn-primary">Submit</button>
        </div>
    </div>

</fieldset>
<?php echo $this->form()->closeTag($form); ?>

the form:

<?php

namespace ZF2FileUploadExamples\Form;

use Zend\InputFilter;
use Zend\Form\Form;
use Zend\Form\Element;

class CollectionUpload extends Form
{
    public $numFileElements = 2;

    public function __construct($name = null, $options = array())
    {
        parent::__construct($name, $options);
        $this->addElements();
        $this->setInputFilter($this->createInputFilter());
    }

    public function addElements()
    {
        // File Input
        $file = new Element\File('file');
        $file->setLabel('Multi File');

        $fileCollection = new Element\Collection('file-collection');
        $fileCollection->setOptions(array(
             'count'          => $this->numFileElements,
             'allow_add'      => false,
             'allow_remove'   => false,
             'target_element' => $file,
        ));
        $this->add($fileCollection);

        // Text Input
        $text = new Element\Text('text');
        $text->setLabel('Text Entry');
        $this->add($text);
    }

    public function createInputFilter()
    {
        $inputFilter = new InputFilter\InputFilter();

        // File Collection
        $fileCollection = new InputFilter\InputFilter();
        for ($i = 0; $i < $this->numFileElements; $i++) {
            $file = new InputFilter\FileInput($i);
            $file->setRequired(true);
            $file->getFilterChain()->attachByName(
                'filerenameupload',
                array(
                    'target'          => './data/tmpuploads/',
                    'overwrite'       => true,
                    'use_upload_name' => true,
                )
            );
            $fileCollection->add($file);
        }
        $inputFilter->add($fileCollection, 'file-collection');

        // Text Input
        $text = new InputFilter\Input('text');
        $text->setRequired(true);
        $inputFilter->add($text);

        return $inputFilter;
    }
}

Solution

  • I don't see where you're setting the data to the form, which may be why it isn't maintained upon rendering form errors.

    You should be probably calling $form->setData($prg); before validating the form.

    My basic logic usually looks like this:

    if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
        return $prg; // Return PRG redirect response
    } elseif ($prg !== false) {
        // Set data to form
        $form->setData($prg);
    
        // Validate form
        if ($form->isValid()) {
             // ...Save the form...
        } else {
            // Do something else
        }
    } else {
          // first time Page is called
    }
    
    // Always show form
    return new ViewModel(array('form' => $form));