Difference between #3 and #2 of Additional form data with XUpload

unchanged
Title
Additional form data with XUpload
unchanged
Category
How-tos
unchanged
Tags
xupload, File upload, form, widget, tutorial, How to
changed
Content
In this article you'll learn how to send additional form data when uploading
files using [XUpload](http://www.yiiframework.com/extension/xupload/
"XUpload") widget

This are the steps that we need:

1. Duplicate and edit the upload form template, so we can render the fields for
the additional data
2. Duplicate and edit the download form template, so we can render the
additioanl data
3. Create a controller action that will handle the file upload, and the
additional data.
4. Adjust the widget in our view, and add the corresponding javascript


So, lets get started:Before getting started, note that we will be
using a custom model named Image, which will hold all the information submitted
by the widget. in our case the additional attributes defined in this model are
_title_ and _description_.

Duplicate and edit the upload form template
----------------------------------

We need our own version of the upload template, so we can add the new fields for
the additional data that we want to send along with the file. to do that, copy
the _upload.php_ template included with the plugin, to your controller's views
folder.

Assuming a default installation, the path to the template should be:

`protected/extensions/xupload/views/upload.php`

Assuming your controller its SiteController, your copy of the template should go
to:

`protected/views/site/upload.php`

To add our new fields, add a new column ( `td` ) to the template, so it looks
like this:



~~~
[php]
<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-upload fade">
        <td class="preview">
            <span class="fade"></span>
        </td>
        <td class="name">
            <span>{%=file.name%}</span>
        </td>
        <td>//This is the new column, and below we add 2 new fields
            <label>Title</label>
            <input type="text" name="title" required
/><br />
            <label>Description</label>
            <textarea name="description" rows="3"
required ></textarea><br />
        </td>
        <td
class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
        {% if (file.error) { %}
            <td class="error" colspan="2"><span
class="label
label-important">{%=locale.fileupload.error%}</span>
{%=locale.fileupload.errors[file.error] || file.error%}</td>
        {% } else if (o.files.valid && !i) { %}
            <td>
                <div class="progress progress-success progress-striped
active"><div class="bar"
style="width:0%;"></div></div>
            </td>
            <td class="start">{% if (!o.options.autoUpload) { %}
                <button class="btn btn-primary">
                    <i class="icon-upload icon-white"></i>
                    <span>{%=locale.fileupload.start%}</span>
                </button>
            {% } %}</td>
        {% } else { %}
            <td colspan="2"></td>
        {% } %}
        <td class="cancel">{% if (!i) { %}
            <button class="btn btn-warning">
                <i class="icon-ban-circle icon-white"></i>
                <span>{%=locale.fileupload.cancel%}</span>
            </button>
        {% } %}</td>
    </tr>
{% } %}
</script>

~~~

We added to new fields to our template - title and description - the rest of the
template remains the same


Duplicate and edit the uploaddownload form template
----------------------------------

To show the info in those fields after the files have been uploaded, we need to
adjust our download template. 

Assuming a default installation, the path to the template should be:

`protected/extensions/xupload/views/download.php`

Assuming your controller its SiteController, your copy of the template should go
to:

`protected/views/site/download.php`

Now, the server returns a Json with the info of the uploaded file, in the
following step we will create the action in the controller that returns that
json including the additional fields. but for now, lets assume they are there so
we can edit our template acordingly.



~~~
[php]
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-download fade">
        {% if (file.error) { %}
            <td></td>
            <td
class="name"><span>{%=file.name%}</span></td>
            <td
class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
            <td class="error" colspan="2"><span
class="label
label-important">{%=locale.fileupload.error%}</span>
{%=locale.fileupload.errors[file.error] || file.error%}</td>
        {% } else { %}
            <td class="preview">{% if (file.thumbnail_url) { %}
                <a href="{%=file.url%}"
title="{%=file.name%}" rel="gallery"
download="{%=file.name%}"><img
src="{%=file.thumbnail_url%}"></a>
            {% } %}</td>
            <td class="name">
                <a href="{%=file.url%}"
title="{%=file.name%}"
rel="{%=file.thumbnail_url&&'gallery'%}"
download="{%=file.name%}">{%=file.name%}</a>
            </td>
            <td
class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
            <td>{%=file.title%}</td>//Here we show the file title
            <td>{%=file.description%}</td>//and the file description
        {% } %}
        <td class="delete">
            <button class="btn btn-danger"
data-type="{%=file.delete_type%}"
data-url="{%=file.delete_url%}">
                <i class="icon-trash icon-white"></i>
                <span>{%=locale.fileupload.destroy%}</span>
            </button>
            <input type="checkbox" name="delete"
value="1">
        </td>
    </tr>
{% } %}
</script>

~~~

We only added the title and the description of the file to the template, nothing
else was changed.


Create a controller action
--------------------------

Now we need a controller actions that will not only handle the file upload, but
also initialize our model's attributes and return the json with the additional
data.

The code here is just a copy of the contents of the XUploadAction, so it doesn't
save anything to the database, or does anything fancy. 




~~~
[php]
public function actionUploadAdditional(){
 		header( 'Vary: Accept' );
        if( isset( $_SERVER['HTTP_ACCEPT'] ) && (strpos(
$_SERVER['HTTP_ACCEPT'], 'application/json' ) !== false) ) {
            header( 'Content-type: application/json' );
        } else {
            header( 'Content-type: text/plain' );
        }

        if( isset( $_GET["_method"] ) ) {
            if( $_GET["_method"] == "delete" ) {
                $success = is_file( $_GET["file"] ) &&
$_GET["file"][0] !== '.' && unlink( $_GET["file"] );
                echo json_encode( $success );
            }
        } else {
            $this->init( );
            $model = new Image;//Here we instantiate our model

            //We get the uploaded instance
            $model->file = CUploadedFile::getInstance( $model, 'file' );
            if( $model->file !== null ) {
                $model->mime_type = $model->file->getType( );
                $model->size = $model->file->getSize( );
                $model->name = $model->file->getName( );
                //Initialize the ddditional Fields, note that we retrieve the
                //fields as if they were in a normal $_POST array
                $model->title = Yii::app()->request->getPost('title',
'');
                $model->description  =
Yii::app()->request->getPost('description', '');

                if( $model->validate( ) ) {
                    $path = Yii::app() -> getBasePath() .
"/../images/uploads";
                    $publicPath =
Yii::app()->getBaseUrl()."/images/uploads";
                    if( !is_dir( $path ) ) {
                        mkdir( $path, 0777, true );
                        chmod ( $path , 0777 );
                    }
                    $model->file->saveAs( $path.$model->name );
                    chmod( $path.$model->name, 0777 );

                    //Now we return our json
                    echo json_encode( array( array(
                            "name" => $model->name,
                            "type" => $model->mime_type,
                            "size" => $model->size,
                            //Add the title 
                            "title" => $model->title,
                            //And the description
                            "description" =>
$model->description,
                            "url" => $publicPath.$model->name,
                            "thumbnail_url" =>
$publicPath.$model->name,
                            "delete_url" => $this->createUrl(
"upload", array(
                                "_method" => "delete",
                                "file" => $path.$model->name
                            ) ),
                            "delete_type" => "POST"
                        ) ) );
                } else {
                    echo json_encode( array( array( "error" =>
$model->getErrors( 'file' ), ) ) );
                    Yii::log( "XUploadAction:
".CVarDumper::dumpAsString( $model->getErrors( ) ),
CLogger::LEVEL_ERROR, "xupload.actions.XUploadAction" );
                }
            } else {
                throw new CHttpException( 500, "Could not upload file"
);
            }
        }
	}
~~~

Thats all we need to get the additional fields we sent from out widget, saving
to the database or changing the folders where you wish your files to be saved,
or generating thumnails, etc. its up to you, you can check the [XUpload
workflow](http://www.yiiframework.com/wiki/348/xupload-workflow/ "XUpload
Workflow") wiki for examples on that.


Adjust the widget, and add javascript
------------------------------------

Now that we have everything setup, we just need to configure our widget to use
our templates, and point to our action. also we need some additional javascript
as explained in the original [jquery plugin
wiki](https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-submit-additional-form-data
"jquery plugin wiki")



~~~
[php]
<?php
		$this->widget('xupload.XUpload', array(
			'url' => Yii::app()->createUrl("site/uploadAdditional",
array("parent_id" => 1)),
			'model' => $model,//An instance of our model
			'attribute' => 'file',
            'multiple' => true,
            //Our custom upload template
            'uploadView' => 'application.views.site.upload',
            //our custom download template
            'downloadView' => 'application.views.site.download',
			'options' => array(//Additional javascript options
                //This is the submit callback that will gather
                //the additional data  corresponding to the current file
                'submit' => "js:function (e, data) {
                    var inputs = data.context.find(':input');
                    data.formData = inputs.serializeArray();
                    return true;
                }"
            ),
		));
		?>
~~~

Thats it, if you need additional help don't hesitate asking in the [official
forum
thread](http://www.yiiframework.com/forum/index.php?/topic/19277-extension-xupload/page__gopid__94404#entry94404
"official forum thread").