ORIENT/modules/backend/formwidgets/FileUpload.php

467 lines
13 KiB
PHP
Raw Normal View History

2014-05-14 13:24:20 +00:00
<?php namespace Backend\FormWidgets;
use Str;
2014-05-14 13:24:20 +00:00
use Input;
use Request;
use Response;
2014-05-14 13:24:20 +00:00
use Validator;
2014-12-05 07:35:42 +00:00
use Backend\Classes\FormField;
2014-05-14 13:24:20 +00:00
use Backend\Classes\FormWidgetBase;
use Backend\Controllers\Files as FilesController;
use October\Rain\Filesystem\Definitions as FileDefinitions;
use ApplicationException;
2015-01-28 07:03:35 +00:00
use ValidationException;
use Exception;
2014-05-14 13:24:20 +00:00
/**
* File upload field
* Renders a form file uploader field.
*
* Supported options:
* - mode: image-single, image-multi, file-single, file-multi
* - upload-label: Add file
* - empty-label: No file uploaded
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
class FileUpload extends FormWidgetBase
{
use \Backend\Traits\FormModelWidget;
//
// Configurable properties
//
2014-05-14 13:24:20 +00:00
2015-06-13 00:41:00 +00:00
/**
* @var string Prompt text to display for the upload button.
2015-06-13 00:41:00 +00:00
*/
public $prompt = null;
2015-06-13 00:41:00 +00:00
/**
* @var int Preview image width
*/
public $imageWidth = null;
/**
* @var int Preview image height
*/
public $imageHeight = null;
/**
* @var mixed Collection of acceptable file types.
*/
public $fileTypes = false;
/**
* @var mixed Collection of acceptable mime types.
*/
public $mimeTypes = false;
/**
* @var array Options used for generating thumbnails.
*/
public $thumbOptions = [
'mode' => 'crop',
'extension' => 'auto'
];
/**
* @var boolean Allow the user to set a caption.
*/
public $useCaption = true;
/**
* @var boolean Automatically attaches the uploaded file on upload if the parent record exists instead of using deferred binding to attach on save of the parent record. Defaults to false.
*/
public $attachOnUpload = false;
//
// Object properties
//
/**
2017-03-15 19:26:14 +00:00
* @inheritDoc
*/
protected $defaultAlias = 'fileupload';
2014-05-14 13:24:20 +00:00
/**
2017-03-15 19:26:14 +00:00
* @inheritDoc
2014-05-14 13:24:20 +00:00
*/
public function init()
{
$this->fillFromConfig([
2015-06-13 00:41:00 +00:00
'prompt',
'imageWidth',
'imageHeight',
'fileTypes',
'mimeTypes',
'thumbOptions',
'useCaption',
'attachOnUpload',
]);
if ($this->formField->disabled) {
$this->previewMode = true;
}
2014-05-14 13:24:20 +00:00
$this->checkUploadPostback();
}
/**
2017-03-15 19:26:14 +00:00
* @inheritDoc
2014-05-14 13:24:20 +00:00
*/
public function render()
{
$this->prepareVars();
return $this->makePartial('fileupload');
2014-05-14 13:24:20 +00:00
}
/**
* Prepares the view data
*/
protected function prepareVars()
2014-05-14 13:24:20 +00:00
{
if ($this->previewMode) {
$this->useCaption = false;
}
$this->vars['fileList'] = $fileList = $this->getFileList();
$this->vars['singleFile'] = $fileList->first();
2014-05-14 13:24:20 +00:00
$this->vars['displayMode'] = $this->getDisplayMode();
2016-02-20 06:12:41 +00:00
$this->vars['emptyIcon'] = $this->getConfig('emptyIcon', 'icon-upload');
2014-05-14 13:24:20 +00:00
$this->vars['imageHeight'] = $this->imageHeight;
$this->vars['imageWidth'] = $this->imageWidth;
$this->vars['acceptedFileTypes'] = $this->getAcceptedFileTypes(true);
$this->vars['cssDimensions'] = $this->getCssDimensions();
2015-06-30 08:27:16 +00:00
$this->vars['cssBlockDimensions'] = $this->getCssDimensions('block');
$this->vars['useCaption'] = $this->useCaption;
$this->vars['prompt'] = $this->getPromptText();
2014-05-14 13:24:20 +00:00
}
protected function getFileList()
{
$list = $this
->getRelationObject()
->withDeferred($this->sessionKey)
->orderBy('sort_order')
->get()
;
2014-05-14 13:24:20 +00:00
2014-08-01 08:14:39 +00:00
/*
* Decorate each file with thumb and custom download path
2014-08-01 08:14:39 +00:00
*/
$list->each(function ($file) {
$this->decorateFileAttributes($file);
});
2014-08-01 08:14:39 +00:00
2014-05-14 13:24:20 +00:00
return $list;
}
/**
* Returns the display mode for the file upload. Eg: file-multi, image-single, etc.
* @return string
*/
2014-05-14 13:24:20 +00:00
protected function getDisplayMode()
{
$mode = $this->getConfig('mode', 'image');
2014-10-10 21:50:05 +00:00
if (str_contains($mode, '-')) {
2014-05-14 13:24:20 +00:00
return $mode;
2014-10-10 21:50:05 +00:00
}
2014-05-14 13:24:20 +00:00
$relationType = $this->getRelationType();
2014-05-14 13:24:20 +00:00
$mode .= ($relationType == 'attachMany' || $relationType == 'morphMany') ? '-multi' : '-single';
return $mode;
}
/**
* Returns the escaped and translated prompt text to display according to the type.
* @return string
*/
protected function getPromptText()
{
if ($this->prompt === null) {
$isMulti = ends_with($this->getDisplayMode(), 'multi');
$this->prompt = $isMulti
? 'backend::lang.fileupload.upload_file'
: 'backend::lang.fileupload.default_prompt';
}
return str_replace('%s', '<i class="icon-upload"></i>', e(trans($this->prompt)));
}
/**
* Returns the CSS dimensions for the uploaded image,
* uses auto where no dimension is provided.
2015-06-30 08:27:16 +00:00
* @param string $mode
* @return string
*/
2015-06-30 08:27:16 +00:00
protected function getCssDimensions($mode = null)
{
if (!$this->imageWidth && !$this->imageHeight) {
return '';
}
$cssDimensions = '';
2015-06-30 08:27:16 +00:00
if ($mode == 'block') {
$cssDimensions .= ($this->imageWidth)
? 'width: '.$this->imageWidth.'px;'
: 'width: '.$this->imageHeight.'px;';
$cssDimensions .= ($this->imageHeight)
? 'height: '.$this->imageHeight.'px;'
: 'height: auto;';
}
else {
$cssDimensions .= ($this->imageWidth)
? 'width: '.$this->imageWidth.'px;'
: 'width: auto;';
$cssDimensions .= ($this->imageHeight)
? 'height: '.$this->imageHeight.'px;'
: 'height: auto;';
}
return $cssDimensions;
}
/**
* Returns the specified accepted file types, or the default
* based on the mode. Image mode will return:
* - jpg,jpeg,bmp,png,gif,svg
* @return string
*/
public function getAcceptedFileTypes($includeDot = false)
{
$types = $this->fileTypes;
if ($types === false) {
$isImage = starts_with($this->getDisplayMode(), 'image');
$types = implode(',', FileDefinitions::get($isImage ? 'imageExtensions' : 'defaultExtensions'));
2015-02-14 10:38:49 +00:00
}
if (!$types || $types == '*') {
2015-02-14 10:38:49 +00:00
return null;
}
if (!is_array($types)) {
$types = explode(',', $types);
}
$types = array_map(function ($value) use ($includeDot) {
$value = trim($value);
if (substr($value, 0, 1) == '.') {
$value = substr($value, 1);
}
if ($includeDot) {
$value = '.'.$value;
}
return $value;
}, $types);
2015-12-04 21:47:07 +00:00
return implode(',', $types);
}
2014-05-14 13:24:20 +00:00
/**
* Removes a file attachment.
*/
public function onRemoveAttachment()
{
2016-04-05 09:47:06 +00:00
$fileModel = $this->getRelationModel();
if (($fileId = post('file_id')) && ($file = $fileModel::find($fileId))) {
2014-09-06 11:46:19 +00:00
$this->getRelationObject()->remove($file, $this->sessionKey);
2014-05-14 13:24:20 +00:00
}
}
/**
* Sorts file attachments.
*/
public function onSortAttachments()
{
if ($sortData = post('sortOrder')) {
$ids = array_keys($sortData);
$orders = array_values($sortData);
2016-04-05 09:47:06 +00:00
$fileModel = $this->getRelationModel();
$fileModel->setSortableOrder($ids, $orders);
2014-05-14 13:24:20 +00:00
}
}
/**
* Loads the configuration form for an attachment, allowing title and description to be set.
*/
public function onLoadAttachmentConfig()
{
2016-04-05 09:47:06 +00:00
$fileModel = $this->getRelationModel();
if (($fileId = post('file_id')) && ($file = $fileModel::find($fileId))) {
$file = $this->decorateFileAttributes($file);
2014-05-14 13:24:20 +00:00
$this->vars['file'] = $file;
$this->vars['displayMode'] = $this->getDisplayMode();
$this->vars['cssDimensions'] = $this->getCssDimensions();
$this->vars['relationManageId'] = post('manage_id');
$this->vars['relationField'] = post('_relation_field');
2014-05-14 13:24:20 +00:00
return $this->makePartial('config_form');
}
throw new ApplicationException('Unable to find file, it may no longer exist');
2014-05-14 13:24:20 +00:00
}
/**
* Commit the changes of the attachment configuration form.
*/
public function onSaveAttachmentConfig()
{
try {
2016-04-05 09:47:06 +00:00
$fileModel = $this->getRelationModel();
if (($fileId = post('file_id')) && ($file = $fileModel::find($fileId))) {
2014-05-14 13:24:20 +00:00
$file->title = post('title');
$file->description = post('description');
$file->save();
return ['displayName' => $file->title ?: $file->file_name];
2014-05-14 13:24:20 +00:00
}
throw new ApplicationException('Unable to find file, it may no longer exist');
}
catch (Exception $ex) {
2014-05-14 13:24:20 +00:00
return json_encode(['error' => $ex->getMessage()]);
}
}
/**
2017-03-15 19:26:14 +00:00
* @inheritDoc
2014-05-14 13:24:20 +00:00
*/
protected function loadAssets()
2014-05-14 13:24:20 +00:00
{
2014-05-24 06:57:38 +00:00
$this->addCss('css/fileupload.css', 'core');
$this->addJs('js/fileupload.js', 'core');
2014-05-14 13:24:20 +00:00
}
/**
2017-03-15 19:26:14 +00:00
* @inheritDoc
*/
2015-01-04 22:43:39 +00:00
public function getSaveValue($value)
{
2014-12-05 07:35:42 +00:00
return FormField::NO_SAVE_DATA;
}
2014-05-14 13:24:20 +00:00
/**
* Checks the current request to see if it is a postback containing a file upload
* for this particular widget.
*/
protected function checkUploadPostback()
{
if (!($uniqueId = Request::header('X-OCTOBER-FILEUPLOAD')) || $uniqueId != $this->getId()) {
2014-05-14 13:24:20 +00:00
return;
2014-10-10 21:50:05 +00:00
}
2014-05-14 13:24:20 +00:00
try {
2015-04-13 11:51:22 +00:00
if (!Input::hasFile('file_data')) {
2015-04-12 09:58:28 +00:00
throw new ApplicationException('File missing from request');
}
2014-05-14 13:24:20 +00:00
2016-04-05 09:47:06 +00:00
$fileModel = $this->getRelationModel();
2015-04-13 11:51:22 +00:00
$uploadedFile = Input::file('file_data');
2016-04-05 09:47:06 +00:00
$validationRules = ['max:'.$fileModel::getMaxFilesize()];
if ($fileTypes = $this->getAcceptedFileTypes()) {
$validationRules[] = 'extensions:'.$fileTypes;
}
if ($this->mimeTypes) {
$validationRules[] = 'mimes:'.$this->mimeTypes;
2014-10-10 21:50:05 +00:00
}
2014-05-14 13:24:20 +00:00
$validation = Validator::make(
['file_data' => $uploadedFile],
['file_data' => $validationRules]
);
2014-10-10 21:50:05 +00:00
if ($validation->fails()) {
2014-05-14 13:24:20 +00:00
throw new ValidationException($validation);
2014-10-10 21:50:05 +00:00
}
2014-05-14 13:24:20 +00:00
2014-10-10 21:50:05 +00:00
if (!$uploadedFile->isValid()) {
throw new ApplicationException('File is not valid');
2014-10-10 21:50:05 +00:00
}
2014-05-14 13:24:20 +00:00
2014-09-06 11:46:19 +00:00
$fileRelation = $this->getRelationObject();
2014-05-14 13:24:20 +00:00
2016-04-05 09:47:06 +00:00
$file = $fileModel;
2014-05-14 13:24:20 +00:00
$file->data = $uploadedFile;
$file->is_public = $fileRelation->isPublic();
2014-05-14 13:24:20 +00:00
$file->save();
/**
* Attach directly to the parent model if it exists and attachOnUpload has been set to true
* else attach via deferred binding
*/
$parent = $fileRelation->getParent();
if ($this->attachOnUpload && $parent && $parent->exists) {
$fileRelation->add($file);
} else {
$fileRelation->add($file, $this->sessionKey);
}
2014-05-14 13:24:20 +00:00
$file = $this->decorateFileAttributes($file);
$result = [
'id' => $file->id,
'thumb' => $file->thumbUrl,
'path' => $file->pathUrl
];
Response::json($result, 200)->send();
2014-05-14 13:24:20 +00:00
}
catch (Exception $ex) {
Response::json($ex->getMessage(), 400)->send();
2014-05-14 13:24:20 +00:00
}
exit;
2014-05-14 13:24:20 +00:00
}
/**
* Adds the bespoke attributes used internally by this widget.
* - thumbUrl
* - pathUrl
* @return System\Models\File
*/
protected function decorateFileAttributes($file)
{
/*
* File is protected, create a secure public path
*/
if (!$file->isPublic()) {
$path = $thumb = FilesController::getDownloadUrl($file);
if ($this->imageWidth || $this->imageHeight) {
$thumb = FilesController::getThumbUrl($file, $this->imageWidth, $this->imageHeight, $this->thumbOptions);
}
}
/*
* Otherwise use public paths
*/
else {
$path = $thumb = $file->getPath();
if ($this->imageWidth || $this->imageHeight) {
$thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions);
}
}
$file->pathUrl = $path;
$file->thumbUrl = $thumb;
return $file;
}
2014-10-10 21:50:05 +00:00
}