Add file attachments from database

This commit is contained in:
philipp lang 2020-10-27 01:49:52 +01:00
parent 0d433d70e9
commit b649cf6c8a
9 changed files with 222 additions and 276 deletions

View File

@ -5,25 +5,28 @@ namespace Aweos\Resizer\Classes;
use Storage;
use Aweos\Resizer\Models\Setting;
use October\Rain\Database\Attach\Resizer;
use Aweos\Resizer\Models\Attachment;
class CompressJob {
public $path;
public $filename;
public $disk;
public $strategy;
public $sizes;
public $attachment_id;
public $maxFilesize = 1920;
public $disk = 'uploads';
public $fullPath;
public $crop;
public $sizes;
public function fire($job, $data) {
$this->path = $data['path'];
$this->filename = $data['filename'];
$this->disk = $data['disk'];
$this->strategy = $data['strategy'];
$this->attachment_id = $data['attachment_id'];
$this->crop = $data['crop'];
$this->sizes = Setting::get('srcx');
Storage::disk($this->disk)->makeDirectory('cropped');
$this->attachment = Attachment::find($this->attachment_id);
$this->fullPath = Storage::disk($this->disk)->path($this->attachment->source->path);
$this->crop();
$this->createVersions();
}
@ -32,49 +35,35 @@ class CompressJob {
if ($this->crop === null) {
return;
}
$fullPath = Storage::disk($this->disk)->path($this->path.'/'.$this->filename);
Storage::disk($this->disk)->makeDirectory($this->getStrategy()->croppedPath());
$r = Resizer::open($fullPath);
$r = Resizer::open($this->fullPath);
$r->crop(floor($this->crop['x']), floor($this->crop['y']), floor($this->crop['w']), floor($this->crop['h']));
$this->path = $this->getStrategy()->croppedPath($this->filename);
$this->filename = $this->getStrategy()->croppedFilename($this->filename, $this->crop);
$r->save(Storage::disk($this->disk)->path($this->path.'/'.$this->filename));
$r->save($this->fullPath);
}
public function createVersions()
{
$fullPath = Storage::disk($this->disk)->path($this->path.'/'.$this->filename);
[ $width, $height ] = getimagesize($fullPath);
[ $width, $height ] = getimagesize($this->fullPath);
if ($width > $this->maxFilesize) {
$r = Resizer::open($fullPath);
$r = Resizer::open($this->fullPath);
$r->resize($this->maxFilesize, 0);
$r->save($fullPath);
$r->save($this->fullPath);
}
[ $width, $height ] = getimagesize($fullPath);
[ $width, $height ] = getimagesize($this->fullPath);
Storage::disk($this->disk)->makeDirectory($this->getStrategy()->publicPath($this->filename));
Storage::disk($this->disk)->makeDirectory($this->attachment->path);
foreach ($this->sizes as $w) {
$filename = $this->getStrategy()->smallFilename($this->filename, $w);
if ($width < $w) {
continue;
}
$destination = Storage::disk($this->disk)->path($this->getStrategy()->publicPath($this->filename).'/'.$this->getStrategy()->smallFilename($this->filename, $w));
Storage::disk($this->disk)->makeDirectory($this->attachment->path);
$r = Resizer::open($fullPath);
$r = Resizer::open($this->fullPath);
$r->resize($w, 0);
$r->save($destination);
$r->save(Storage::disk($this->disk)->path($this->attachment->getVersionPath($w)));
}
}

View File

@ -4,6 +4,8 @@ namespace Aweos\Resizer\Classes;
use Queue;
use Storage;
use Aweos\Resizer\Models\SourceFile;
use Aweos\Resizer\Models\Attachment;
class UploadStorage {
@ -16,75 +18,57 @@ class UploadStorage {
$this->file = $uploadedFile;
$this->data = $data;
$fileName = $this->getStrategy()->sourceFileBasename($this->file, $this->data);
$sourcePath = $this->getStrategy()->sourcePath($fileName);
$fileName = $this->transformFileName($sourcePath, $fileName).'.'.$this->file->getClientOriginalExtension();
$sourceFile = new SourceFile([
'basename' => pathinfo($this->file->getClientOriginalName(), PATHINFO_FILENAME),
'extension' => $this->file->getClientOriginalExtension(),
'tags' => []
]);
$sourceFile->slugAttributes();
$uploadedFile->storeAs($sourcePath, $fileName, $this->disk);
$uploadedFile->storeAs('', $sourceFile->path, $this->disk);
$sourceFile->save();
$attachment = $sourceFile->attachments()->create([
'title' => $this->data['title'],
'description' => $this->data['description'] ?? ''
]);
Queue::push(CompressJob::class, [
'path' => $sourcePath,
'filename' => $fileName,
'disk' => $this->disk,
'strategy' => $this->strategy,
'attachment_id' => $attachment->id,
'crop' => $this->data['crop']
]);
return $this->getFileData($sourcePath.'/'.$fileName);
return $attachment;
}
public function getFileData($filename) {
$realname = preg_replace('/^source/', 'cropped', $filename);
$realname = $this->storage()->exists($realname) ? $realname : $filename;
public function getFileData($id) {
$attachment = Attachment::find($id);
return [
'url' => $this->storage()->url($realname),
'type' => $this->storage()->mimeType($filename),
'size' => $this->storage()->size($filename),
'name' => pathinfo($filename, PATHINFO_BASENAME)
'url' => $this->storage()->url($attachment->source->path),
'type' => $this->storage()->mimeType($attachment->source->path),
'size' => $this->storage()->size($attachment->source->path),
'name' => $attachment->slug,
'id' => $id
];
}
public function removeFile($filename) {
$sourcePath = $this->getStrategy()->sourcePath($filename).'/'.$filename;
$croppedPath = $this->getStrategy()->croppedPath().'/'.$filename;
public function removeAttachment($id) {
$attachment = Attachment::find($id);
if (!Storage::disk($this->disk)->exists($sourcePath)) {
return;
}
if (Storage::disk($this->disk)->exists($croppedPath)) {
Storage::disk($this->disk)->delete($croppedPath);
}
collect(Storage::disk($this->disk)->files($this->getStrategy()->publicPath($filename)))->filter(function($file) use ($filename) {
return preg_match($this->getStrategy()->versionRegex($filename), pathinfo($file, PATHINFO_BASENAME));
collect(Storage::disk($this->disk)->files($attachment->path))->filter(function($file) use ($attachment) {
return preg_match($attachment->versionRegex, $file);
})->each(function($file) {
Storage::disk($this->disk)->delete($file);
});
Storage::disk($this->disk)->delete($sourcePath);
$attachment->delete();
}
private function storage() {
return Storage::disk($this->disk);
}
private function transformFileName($path, $basename) {
if (count(glob($this->storage()->path($path).'/'.$basename.'*')) == 0) {
return $basename;
}
$i = 1;
while(count(glob($this->storage()->path($path).'/'.$basename.'-'.$i.'*')) != 0) {
$i++;
}
return $basename.'-'.$i;
}
private function originalExtension() {
return $this->file->getClientOriginalExtension();
}

View File

@ -35,51 +35,8 @@ class Responsiveimage extends FormWidgetBase
public $aspectRatio;
/**
* @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
*/
protected $defaultAlias = 'responsiveimage';
/**
* @var Backend\Widgets\Form The embedded form for modifying the properties of the selected file
*/
protected $configFormWidget;
/**
@ -87,8 +44,6 @@ class Responsiveimage extends FormWidgetBase
*/
public function init()
{
$this->maxFilesize = $this->getUploadMaxFilesize();
$this->fillFromConfig([
'minWidth',
'aspectRatio'
@ -121,115 +76,13 @@ class Responsiveimage extends FormWidgetBase
$this->vars['aspectRatio'] = $this->aspectRatio ?: 'null';
$this->vars['minWidth'] = $this->minWidth ?: '0';
$this->vars['name'] = $this->formField->getName();
$this->vars['value'] = str_replace('"', "'", json_encode($this->getLoadValue()));
$this->vars['value'] = $this->getLoadValue() ?: 'null';
$this->vars['meta'] = $this->getLoadValue()
? str_replace('"', "'", json_encode(app(UploadStorage::class)->getFileData($this->getLoadValue())))
: 'null';
$this->vars['model'] = $this->model;
}
/**
* 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;
}
/**
* Removes a file attachment.
*/
public function onRemoveAttachment()
{
//
}
/**
* Loads the configuration form for an attachment, allowing title and description to be set.
*/
public function onLoadAttachmentConfig()
{
//
}
/**
* 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
*/
@ -244,7 +97,7 @@ class Responsiveimage extends FormWidgetBase
*/
public function getSaveValue($value)
{
return $value ? json_decode($value) : null;
return $value;
}
/**
@ -263,51 +116,13 @@ class Responsiveimage extends FormWidgetBase
throw new ApplicationException('File is not valid');
}
$filename = app(UploadStorage::class)->storeFileFromUpload($uploadedFile, $data);
$attachment = app(UploadStorage::class)->storeFileFromUpload($uploadedFile, $data);
return Response::json([
'file' => $filename,
'data' => array_only($data, ['title', 'description'])
], 200);
return Response::make($attachment->id);
}
public function onDelete() {
app(UploadStorage::class)->removeFile(Input::get('fileName'));
app(UploadStorage::class)->removeAttachment(Input::get('file_id'));
}
/**
* 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);
}
}

View File

@ -94,6 +94,7 @@ export default {
components: { vueDropzone },
props: {
meta: {},
cropOptions: {},
name: {
required: true
@ -109,7 +110,7 @@ export default {
return Math.random().toString(36).substring(7);
},
asString() {
return JSON.stringify(this.content);
return this.content;
},
formData() {
return $(this.$el).closest('form').serializeArray();
@ -180,14 +181,14 @@ export default {
onMount() {
if (!this.value) { return; }
this.addVisible = false;
var file = { size: this.value.file.size, name: this.value.file.name, type: this.value.file.type };
this.$refs.dropzone.manuallyAddFile(file, this.value.file.url);
var file = { size: this.meta.size, name: this.meta.name, type: this.meta.type };
this.$refs.dropzone.manuallyAddFile(file, this.meta.url);
},
onRemove(file, error, xhr) {
var _cls = this;
$(this.$el).request(this.handlers.onDelete, {
data: { fileName: file.name },
data: { file_id: this.content },
success: function(data) {
_cls.addVisible = true;
_cls.content = '';

View File

@ -14,6 +14,7 @@
minWidth: <?= $minWidth ?>,
}"
:value="<?= $value; ?>"
:meta="<?= $meta; ?>"
></app>
</div>
</div>

68
models/Attachment.php Normal file
View File

@ -0,0 +1,68 @@
<?php namespace Aweos\Resizer\Models;
use Model;
use Storage;
/**
* Setting Model
*/
class Attachment extends Model
{
use \October\Rain\Database\Traits\Sluggable;
protected $slugs = ['slug' => 'title'];
/**
* @var string The database table used by the model.
*/
public $table = 'responsive_attachments';
/**
* @var array Guarded fields
*/
protected $guarded = ['*'];
/**
* @var array Fillable fields
*/
protected $fillable = ['id', 'file_id', 'title', 'slug', 'description'];
/**
* @var array Relations
*/
public $hasOne = [];
public $hasMany = [];
public $belongsTo = [
'source' => [SourceFile::class, 'key' => 'file_id']
];
public $belongsToMany = [];
public $morphTo = [];
public $morphOne = [];
public $morphMany = [];
public $attachOne = [];
public $attachMany = [];
public function getFilenameAttribute() {
return $this->slug.'.'.$this->source->extension;
}
public function getPathAttribute() {
return strtolower($this->slug[0]);
}
public function getVersionPath($w) {
return $this->path.'/'.$this->slug.'-'.$w.'.'.$this->source->extension;
}
public function getVersionRegexAttribute() {
$path = preg_quote($this->path, '/');
$ext = preg_quote($this->source->extension, '/');
$name = preg_quote($this->slug, '/');
return "/^{$path}\/{$name}(-[0-9]+)?\.{$ext}$/";
}
public function getUrlAttribute() {
return Storage::disk('uploads')->url($this->source->path);
}
}

49
models/SourceFile.php Normal file
View File

@ -0,0 +1,49 @@
<?php namespace Aweos\Resizer\Models;
use Model;
/**
* Setting Model
*/
class SourceFile extends Model
{
use \October\Rain\Database\Traits\Sluggable;
protected $slugs = ['slug' => 'basename'];
/**
* @var string The database table used by the model.
*/
public $table = 'responsive_source_files';
/**
* @var array Guarded fields
*/
protected $guarded = ['*'];
/**
* @var array Fillable fields
*/
protected $fillable = ['id', 'basename', 'extension', 'tags', 'slug'];
public $jsonable = ['tags'];
/**
* @var array Relations
*/
public $hasOne = [];
public $hasMany = [
'attachments' => [Attachment::class, 'key' => 'file_id']
];
public $belongsTo = [];
public $belongsToMany = [];
public $morphTo = [];
public $morphOne = [];
public $morphMany = [];
public $attachOne = [];
public $attachMany = [];
public function getPathAttribute() {
return 'source/'.$this->slug.'.'.$this->extension;
}
}

View File

@ -0,0 +1,36 @@
<?php namespace Aweos\Resizer\Updates;
use Schema;
use October\Rain\Database\Schema\Blueprint;
use October\Rain\Database\Updates\Migration;
class CreateResponsiveFilesTable extends Migration
{
public function up()
{
Schema::create('responsive_source_files', function(Blueprint $table) {
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('basename');
$table->string('slug');
$table->string('extension');
$table->json('tags');
$table->timestamps();
});
Schema::create('responsive_attachments', function(Blueprint $table) {
$table->engine = 'InnoDB';
$table->increments('id');
$table->integer('file_id')->unsigned();
$table->string('title');
$table->string('slug');
$table->string('description')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('aweos_resizer_settings');
}
}

View File

@ -1 +1,4 @@
1.0.1: First version of resizer
1.0.2:
- Create attachments
- create_file_attachments_table.php