Development Uploader

From Cloudrexx Development Wiki
Jump to: navigation, search

Introduction

The new uploader modal

The Uploader provides the ability to upload files in Cloudrexx through an easy and intuitive user interface. It supports drag&drop file selection and preview selected images.

Note: This documentation refers to version 5 or newer. For older versions of Cloudrexx, please refer to Uploader pre 5.

Integration

To initialize the uploader do create a new instance of \Cx\Core_Modules\Uploader\Model\Entity\Uploader in your code. This should normally be done within the Frontend- or BackendController.

For our simple example we use the DefaultUploadCallback class which just uploads the files into the /image/content/ folder of your Cloudrexx installation.

With the method getXHtml() you can get the generated html code for the uploader button. You can then use this in combination with the Sigma template to add the button somewhere in your template, by calling the setVariable method like shown below.

For the example below to work you have to have a placeholder with the name UPLOADER_CODE in your template, else the uploader won't be visible.


Example code for modules/<component>/Controller/BackendController.class.php

public function parsePage(\Cx\Core\Html\Sigma $template, array $cmd, &$isSingle = false) {
    $uploader = new \Cx\Core_Modules\Uploader\Model\Entity\Uploader();
    $uploader->setFinishedCallback(
        '\Cx\Core_Modules\Uploader\Model\DefaultUploadCallback'
    );
    $template->setVariable(
        // Placeholder in the template
        'UPLOADER_CODE',
        // Fetch HTML-button-element
        // The passed argument is used as label of the button element
        $uploader->getXHtml('Open Uploader')
    );
}

Example code for modules/<component>/View/Template/Backend/Default.html

{UPLOADER_CODE}

Modal window vs Inline Uploader

By default, the Uploader will be opened in a modal window. However, it is possible to integrate the Uploader as an inline widget. To do so, do change the type as follows:

$uploader->setType(\Cx\Core_Modules\Uploader\Model\Entity\Uploader::UPLOADER_TYPE_INLINE);

Callback handling

Server-side (PHP)

To specify a callback you can provide a class which implements the \Cx\Core_Modules\Uploader\Model\UploadCallbackInterface

$uploader->setFinishedCallback(
    '\Cx\Core_Modules\Uploader\Model\DefaultUploadCallback'
);

When the upload is finished the Uploader will call the uploadFinished method of the class with the specified arguments in the UploadCallbackInterface interface.

/**
 * @param $tempPath String Path to the temporary directory containing the files at this moment.
 * @param $tempWebPath String Points to the same folder as tempPath, but relative to the webroot.
 * @param $data String Data given to setData() when creating the uploader.
 * @param $uploadId integer Per-session unique id for the current upload.
 * @param $fileInfos array('originalFileNames' => array( 'theCurrentAndCleanedFilename.txt' => 'raw!Source#Filename.txt' ) )
 *
 * @return mixed The return value can be an array as shown in the example or null.
 *               When returning an array, all files left in the temporary directory are moved accordingly.
 *               When returning null, all left files are deleted.
 */
function uploadFinished($tempPath, $tempWebPath, $data, $uploadId, $fileInfos, $response);

You can find a example for a callback in the \Cx\Core_Modules\Uploader\Model\DefaultUploadCallback class. The Uploader injects the \Cx\Core\Core\Controller\Cx instance as a first parameter in the contructor so we don't have to use singeltons or global objects.

The method uploadFinished should return an array with the location where the uploaded file(s) should be moved to.


Client-side (JavaScript)

The Uploader will call a specified JavaScript callback after the upload has finished and the user has closed the Uploader's modal window. The function should be available from the global window context. This function will also be called with an empty array if the user hasn't uploaded anything.

Register JavaScript callback from PHP:

// Function attached to window which gets called when the
// upload window is closed after an successful upload.
$uploader->setCallback('gallery.afterUpload');

Define JavaScript callback in JavaScript:

window.gallery = {
    afterUpload: function(files){
        // The files array contains all uploaded files
    }
}

The first argument passed to the javascript callback is the array with the uploaded files. I.e.:

["/images/content/Screenshot-from-2014-10-01-114138.png", 
 "/images/content/Screenshot-from-2014-10-01-153505.png", 
 "/images/content/Screenshot-from-2014-10-01-162041.png",
 "/images/content/Screenshot-from-2014-10-03-134226.png"]


Legacy callback

If you want to migrate an old module to the new uploader you can still use your old callback:

$uploader->setFinishedCallback(array(
    '/Gallery/Controller/GalleryManager.class.php',
    '\Cx\Modules\Gallery\Controller\GalleryManager',
    'uploadFinished'
));

Example:

function uploadFinished(
    $tempPath, $tempWebPath, $data, $uploadId, $fileInfos
) {
    return array(
        $this->cx->getWebsiteImagesContentPath(),
        $this->cx->getWebsiteImagesContentWebPath()
    );
}

Pass additional data arguments

To pass additional data to the server-side callback method, do set them through setData():

$uploader->setData(array(
    'foo' => 'bar'
));

The data can then be accessed through the $data argument in the callback method:

function uploadFinished($tempPath, $tempWebPath, $data, $uploadId, $fileInfos, $response){
   // array(1) {
   //     "foor"]=> string(3) "bar"
   // }
   var_dump($data)
}

Resume existing upload session

To resume an existing upload session, do pass the ID of the upload session as argument on object instantiation:

$uploader = \Cx\Core_Modules\Uploader\Model\Entity\Uploader($id);

The ID of an existing upload session is available through Uploader::getId()

$id = $uploader->getId();

Use Uploader::isValidId() to verify an ID's validity:

if (!\Cx\Core_Modules\Uploader\Model\Entity\Uploader::isValidId($id)) {
    throw new \Exception('Invalid ID');
}

Drop upload session

To clean up the user session after a successful upload, completed upload sessions can be dropped as follows:

\Cx\Core_Modules\Uploader\Model\Entity\Uploader::destroy($id);

Options

File count limit

You can specify how many files the user can upload by using the method setUploadLimit.

$uploader->setUploadLimit(1);

File size limit

Restrict the upload to a maximum file size limit. The method accepts numeric or formatted string values, e.g.: 204800 or "204800b" or "200kb".

$uploader->setMaxFileSize('10mb');

File extension restriction

Restrict the set of allowed file extensions to be uploaded through option allowed-extensions:

$uploader->setOptions(array(
    'allowed-extensions' => array('jpg', 'jpeg', 'png', 'gif')
));

Button customization

Customize the layout of the HTML-button-element by setting any valid button-attribute:

// set html attributes for styling or javascript
$uploader->setOptions(
    array(
        'id' => 'page_target_browse',
        'type' => 'button'
    )
);

Or add additional CSS classes as follows:

$uploader->addClass('fancy-button');

Image preview

When the Uploader is being used as an image selector, then it can be set up with a real-time image preview functionality on a selected HTML-img element:

$uploader->setOptions(array(
    'data-thumb-selector' => '#img-preview',
    'data-thumb-max-width' => 120,
    'data-thumb-max-height' => 120,
));

Explanation of options:

Option name Description
data-thumb-selector jQuery selector to identify the HTMl-img element on which the selected image shall be previewed.
data-thumb-max-width Width of the preview image
data-thumb-max-height Height of the preview image

Migrating from the old uploader

First we have to remove all the calls to the old uploader:

/**
 * Name of the upload instance
 */
$uploaderInstanceName = 'exposed_combo_uploader';
$uploaderWidgetName = 'uploadWidget';
/**
 * jQuery selector of the HTML-element where the upload folder-widget shall be put in
 */
$uploaderFolderWidgetContainer = '#uploadFormField_uploadWidget';
$uploader = \Cx\Core_Modules\Upload\Controller\UploadFactory::getInstance()->newUploader('exposedCombo');

And replace them with the instance of the new uploader:

$uploader = new \Cx\Core_Modules\Uploader\Model\Entity\Uploader();

Then we can migrate the callback to the new uploader. The name of the method is the same for the new and old uploader, so if your new uploader instance is created with the same name ($uploader) you can leave it as it is.

$uploader->setFinishedCallback(array('/Gallery/Controller/GalleryManager.class.php', '\Cx\Modules\Gallery\Controller\GalleryManager', 'uploadFinished')); Working legacy example

Migrating a folder widget associated with the uploader

If you also have a folder widget displaying the files which the user has uploaded you have to migrate this too.

Replace the following code with the new folder widget instance.

$folderWidget = $f->newFolderWidget($tup[0].'/'.$tup[2]);

New code for folder widget instance.

$folderWidget = new \Cx\Core_Modules\MediaBrowser\Model\Entity\FolderWidget($pathToFolder);

To place the folder widget html in the template you can use the getXHtml method.

$template->setVariable(array(
    'FOLDER_WIDGET_CODE' => $folderWidget->getXHtml(),
));

Refresh the folder widget when uploading new files

If you need to refresh the folder widget after you've uploaded a new file you can use the following code:

$uploader->setCallback('JsCallback');
$javascript = "
<script type=\"text/javascript\">
function JsCallback(callback) {
        angular.element('#mediaBrowserfolderWidget_{$folderWidget->getId()}').scope().refreshBrowser();
}
</script>";