2020-10-21 00:02:20 +02:00
|
|
|
<?php namespace Aweos\Resizer\FormWidgets;
|
|
|
|
|
|
|
|
use Db;
|
|
|
|
use Input;
|
|
|
|
use Request;
|
|
|
|
use Response;
|
|
|
|
use Validator;
|
|
|
|
use Backend\Widgets\Form;
|
|
|
|
use Backend\Classes\FormField;
|
|
|
|
use Backend\Classes\FormWidgetBase;
|
|
|
|
use October\Rain\Filesystem\Definitions as FileDefinitions;
|
|
|
|
use ApplicationException;
|
|
|
|
use ValidationException;
|
|
|
|
use Exception;
|
|
|
|
use Aweos\Resizer\Traits\ResponsiveSaver;
|
|
|
|
use Aweos\Resizer\Traits\ResponsiveWidget;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 Responsiveimage extends FormWidgetBase
|
|
|
|
{
|
|
|
|
|
2020-10-25 13:54:01 +01:00
|
|
|
public $minWidth;
|
2020-10-21 00:02:20 +02:00
|
|
|
|
2020-10-25 13:54:01 +01:00
|
|
|
public $aspectRatio;
|
2020-10-21 00:02:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var mixed Collection of acceptable file types.
|
|
|
|
*/
|
|
|
|
public $fileTypes = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var mixed Collection of acceptable mime types.
|
|
|
|
*/
|
|
|
|
public $mimeTypes = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var mixed Max file size.
|
|
|
|
*/
|
|
|
|
public $maxFilesize;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
//
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
2020-10-25 13:54:01 +01:00
|
|
|
protected $defaultAlias = 'responsiveimage';
|
2020-10-21 00:02:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var Backend\Widgets\Form The embedded form for modifying the properties of the selected file
|
|
|
|
*/
|
|
|
|
protected $configFormWidget;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
public function init()
|
|
|
|
{
|
|
|
|
$this->maxFilesize = $this->getUploadMaxFilesize();
|
|
|
|
|
|
|
|
$this->fillFromConfig([
|
2020-10-25 13:54:01 +01:00
|
|
|
'minWidth',
|
|
|
|
'aspectRatio'
|
2020-10-21 00:02:20 +02:00
|
|
|
]);
|
|
|
|
|
2020-10-25 13:54:01 +01:00
|
|
|
/*
|
|
|
|
|
2020-10-21 00:02:20 +02:00
|
|
|
if ($this->formField->disabled) {
|
|
|
|
$this->previewMode = true;
|
|
|
|
}
|
|
|
|
|
2020-10-25 13:54:01 +01:00
|
|
|
//$this->getConfigFormWidget();
|
|
|
|
*/
|
2020-10-21 00:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
public function render()
|
|
|
|
{
|
|
|
|
$this->prepareVars();
|
|
|
|
return $this->makePartial('responsiveimage');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepares the view data
|
|
|
|
*/
|
|
|
|
protected function prepareVars()
|
|
|
|
{
|
2020-10-25 13:54:01 +01:00
|
|
|
$this->vars['aspectRatio'] = $this->aspectRatio;
|
|
|
|
$this->vars['minWidth'] = $this->minWidth;
|
2020-10-21 00:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the file record for this request, returns false if none available
|
|
|
|
*
|
|
|
|
* @return System\Models\File|false
|
|
|
|
*/
|
|
|
|
protected function getFileRecord()
|
|
|
|
{
|
|
|
|
$record = false;
|
|
|
|
|
|
|
|
return $record;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
* @param string $mode
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected function getCssDimensions($mode = null)
|
|
|
|
{
|
|
|
|
if (!$this->imageWidth && !$this->imageHeight) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
$cssDimensions = '';
|
|
|
|
|
|
|
|
if ($mode == 'block') {
|
|
|
|
$cssDimensions .= $this->imageWidth
|
|
|
|
? 'width: '.$this->imageWidth.'px;'
|
|
|
|
: 'width: '.$this->imageHeight.'px;';
|
|
|
|
|
|
|
|
$cssDimensions .= ($this->imageHeight)
|
|
|
|
? 'max-height: '.$this->imageHeight.'px;'
|
|
|
|
: 'height: auto;';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$cssDimensions .= $this->imageWidth
|
|
|
|
? 'width: '.$this->imageWidth.'px;'
|
|
|
|
: 'width: auto;';
|
|
|
|
|
|
|
|
$cssDimensions .= ($this->imageHeight)
|
|
|
|
? 'max-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'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$types || $types == '*') {
|
|
|
|
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);
|
|
|
|
|
|
|
|
return implode(',', $types);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes a file attachment.
|
|
|
|
*/
|
|
|
|
public function onRemoveAttachment()
|
|
|
|
{
|
|
|
|
$fileModel = $this->getRelationModel();
|
|
|
|
if (($fileId = post('file_id')) && ($file = $fileModel::find($fileId))) {
|
|
|
|
$this->getRelationObject()->remove($file, $this->sessionKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorts file attachments.
|
|
|
|
*/
|
|
|
|
public function onSortAttachments()
|
|
|
|
{
|
|
|
|
if ($sortData = post('sortOrder')) {
|
|
|
|
$ids = array_keys($sortData);
|
|
|
|
$orders = array_values($sortData);
|
|
|
|
|
|
|
|
$fileModel = $this->getRelationModel();
|
|
|
|
$fileModel->setSortableOrder($ids, $orders);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads the configuration form for an attachment, allowing title and description to be set.
|
|
|
|
*/
|
|
|
|
public function onLoadAttachmentConfig()
|
|
|
|
{
|
|
|
|
$fileModel = $this->getRelationModel();
|
|
|
|
if ($file = $this->getFileRecord()) {
|
|
|
|
$file = $this->decorateFileAttributes($file);
|
|
|
|
|
|
|
|
$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');
|
|
|
|
|
|
|
|
return $this->makePartial('config_form');
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new ApplicationException('Unable to find file, it may no longer exist');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Commit the changes of the attachment configuration form.
|
|
|
|
*/
|
|
|
|
public function onSaveAttachmentConfig()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
$formWidget = $this->getConfigFormWidget();
|
|
|
|
if ($file = $formWidget->model) {
|
|
|
|
$modelsToSave = $this->prepareModelsToSave($file, $formWidget->getSaveData());
|
|
|
|
Db::transaction(function () use ($modelsToSave, $formWidget) {
|
|
|
|
foreach ($modelsToSave as $modelToSave) {
|
|
|
|
$modelToSave->save(null, $formWidget->getSessionKey());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return ['displayName' => $file->title ?: $file->file_name];
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new ApplicationException('Unable to find file, it may no longer exist');
|
|
|
|
}
|
|
|
|
catch (Exception $ex) {
|
|
|
|
return json_encode(['error' => $ex->getMessage()]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
protected function loadAssets()
|
|
|
|
{
|
2020-10-25 13:54:01 +01:00
|
|
|
$this->addCss('css/responsiveimage.build.css', 'core');
|
|
|
|
$this->addJs('js/responsiveimage.build.js', 'core');
|
2020-10-21 00:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
public function getSaveValue($value)
|
|
|
|
{
|
|
|
|
return FormField::NO_SAVE_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Upload handler for the server-side processing of uploaded files
|
|
|
|
*/
|
|
|
|
public function onUpload()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
if (!Input::hasFile('file_data')) {
|
|
|
|
throw new ApplicationException('File missing from request');
|
|
|
|
}
|
|
|
|
|
|
|
|
$fileModel = $this->getRelationModel();
|
|
|
|
$uploadedFile = Input::file('file_data');
|
|
|
|
|
|
|
|
$validationRules = ['max:'.$fileModel::getMaxFilesize()];
|
|
|
|
if ($fileTypes = $this->getAcceptedFileTypes()) {
|
|
|
|
$validationRules[] = 'extensions:'.$fileTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->mimeTypes) {
|
|
|
|
$validationRules[] = 'mimes:'.$this->mimeTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
$validation = Validator::make(
|
|
|
|
['file_data' => $uploadedFile],
|
|
|
|
['file_data' => $validationRules]
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($validation->fails()) {
|
|
|
|
throw new ValidationException($validation);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$uploadedFile->isValid()) {
|
|
|
|
throw new ApplicationException('File is not valid');
|
|
|
|
}
|
|
|
|
|
|
|
|
$fileRelation = $this->getRelationObject();
|
|
|
|
|
|
|
|
$file = $fileModel;
|
|
|
|
$file->data = $uploadedFile;
|
|
|
|
$file->is_public = $fileRelation->isPublic();
|
|
|
|
$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);
|
|
|
|
}
|
|
|
|
|
|
|
|
$file = $this->decorateFileAttributes($file);
|
|
|
|
|
|
|
|
$result = [
|
|
|
|
'id' => $file->id,
|
|
|
|
'thumb' => $file->thumbUrl,
|
|
|
|
'path' => $file->pathUrl
|
|
|
|
];
|
|
|
|
|
|
|
|
$response = Response::make($result, 200);
|
|
|
|
}
|
|
|
|
catch (Exception $ex) {
|
|
|
|
$response = Response::make($ex->getMessage(), 400);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds the bespoke attributes used internally by this widget.
|
|
|
|
* - thumbUrl
|
|
|
|
* - pathUrl
|
|
|
|
* @return System\Models\File
|
|
|
|
*/
|
|
|
|
protected function decorateFileAttributes($file)
|
|
|
|
{
|
|
|
|
$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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return max upload filesize in Mb
|
|
|
|
* @return integer
|
|
|
|
*/
|
|
|
|
protected function getUploadMaxFilesize()
|
|
|
|
{
|
|
|
|
$size = ini_get('upload_max_filesize');
|
|
|
|
if (preg_match('/^([\d\.]+)([KMG])$/i', $size, $match)) {
|
|
|
|
$pos = array_search($match[2], ['K', 'M', 'G']);
|
|
|
|
if ($pos !== false) {
|
|
|
|
$size = $match[1] * pow(1024, $pos + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return floor($size / 1024 / 1024);
|
|
|
|
}
|
|
|
|
}
|