first commit

This commit is contained in:
2017-10-03 17:05:46 +02:00
commit 0ddc6e835a
11 changed files with 496 additions and 0 deletions

View File

@@ -0,0 +1,129 @@
<?php
namespace Meoran\Images\Http\Controllers;
use Closure;
use Laravel\Lumen\Routing\Controller as BaseController;
use Meoran\Images\Model\Image;
class ImagesController extends BaseController
{
public function get($template, $filename)
{
switch (strtolower($template)) {
case 'original':
return $this->getOriginal($filename);
case 'download':
return $this->getDownload($filename);
default:
return $this->getImage($template, $filename);
}
}
public function upload()
{
$pathImage = storage_path('Sunset_at_Tiergarten_UHD.jpg');
$image = new Image(['content' => $pathImage]);
$image->save();
return response()->json($image);
}
private function getOriginal($filename)
{
$path = $this->getImagePathOrAbort($filename);
return $this->buildResponse(file_get_contents($path));
}
private function getDownload($filename)
{
$response = $this->getOriginal($filename);
return $response->header(
'Content-Disposition',
'attachment; filename=' . $filename
);
}
private function getImagePathOrAbort($filename)
{
$path = Image::getAbsolutePath($filename);
if (is_file($path)) {
return $path;
}
abort(404);
}
public function getImage($template, $filename)
{
$template = $this->getTemplate($template);
$path = $this->getImagePathOrAbort($filename);
$lifetime = config('image.lifetime');
if (empty($lifetime)) {
$content = $this->applyTemplate($template,$path)->encode();
} else {
$content = app('image')->cache(function ($image) use ($template, $path) {
$this->applyTemplate($template,$path,$image);
return $image;
}, $lifetime);
}
return $this->buildResponse($content);
}
private function applyTemplate($template, $path, $image = null)
{
if (empty($image)) {
$image = app('image');
}
if ($template instanceof Closure) {
// build from closure callback template
return $template($image->make($path));
} else {
// build from filter template
return $image->make($path)->filter($template);
}
}
/**
* Returns corresponding template object from given template name
*
* @param string $template
* @return mixed
*/
private function getTemplate($template)
{
$template = config("image.templates.{$template}");
switch (true) {
// closure template found
case is_callable($template):
return $template;
// filter template found
case class_exists($template):
return new $template;
default:
// template not found
abort(404);
break;
}
}
private function buildResponse($content)
{
// define mime type
$mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $content);
// return http response
return response($content, 200, array(
'Content-Type' => $mime,
'Cache-Control' => 'max-age=' . (config('image.lifetime') * 60) . ', public',
'Etag' => md5($content)
));
}
}

140
src/Model/Image.php Executable file
View File

@@ -0,0 +1,140 @@
<?php
namespace Meoran\Images\Model;
use Illuminate\Database\Eloquent\Model;
use Spatie\ImageOptimizer\OptimizerChain;
/**
* Class Image
* @property Image $content
* @package App\Model
*/
class Image extends Model
{
protected $_content;
public $fillable = [
'content',
'position',
'created',
'updated'
];
protected $dates = ['created_at', 'updated_at'];
protected $appends = ['url'];
protected $hidden = [];
public function getUrlAttribute()
{
return app('url')->to('/'.config('image.route').'/original/' . $this->filename);
}
protected static function boot()
{
parent::boot();
static::creating(function(Image $model) {
if (empty($model->content)) {
throw new \Exception("Content of picture can't be empty at creation");
}
$model->savePicture();
});
static::updating(function (Image $model) {
$model->savePicture();
});
static::deleted(function (Image $model) {
$model->deletePicture();
});
}
public function getPath()
{
if (empty($this->filename)) {
return null;
}
return self::getAbsolutePath($this->filename);
}
static function getAbsolutePath($filename)
{
$basePath = config('image.path');
$parts = array_slice(str_split($filename, 2), 0, 2);
$path = $basePath.'/'.implode('/', $parts).'/'.$filename;
return $path;
}
static function generateRandomFilename()
{
return mb_strtolower(str_random(60));
}
public function generateFilename($force = false)
{
if ($this->filename && !$force) {
return;
}
$this->filename = self::generateRandomFilename();
}
public function setContentAttribute($content)
{
$this->_content = app('image')->make($content);
}
public function getContentAttribute($value)
{
return $this->_content;
}
protected function savePicture()
{
if (empty($this->content)) {
return true;
}
$this->generateFilename();
return $this->saveContent();
}
protected function saveContent()
{
if (empty($this->content)) {
throw new \InvalidArgumentException("Content is Empty");
}
$path = $this->getPath();
$dir = dirname($path);
if (!is_dir($dir)) {
mkdir($dir, 0775, true);
}
$res = $this->content->save($path);
app(OptimizerChain::class)->optimize($path);
return $res;
}
protected function deletePicture()
{
$path = $this->getPath();
if (is_file($path)) {
return unlink($path);
}
return true;
}
public function toArray()
{
$attributes = parent::toArray();
if (isset($attributes['pivot']) && array_key_exists('position', $attributes['pivot'])) {
$attributes['position'] = $attributes['pivot']['position'];
}
unset($attributes['pivot']);
return $attributes;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Meoran\Images\Providers;
use Illuminate\Support\ServiceProvider;
use Intervention\Image\ImageServiceProvider;
use Spatie\LaravelImageOptimizer\ImageOptimizerServiceProvider;
class ImagesServiceProvider extends ServiceProvider
{
public function boot()
{
require_once __DIR__ . '/../functions.php';
$this->loadMigrationsFrom(__DIR__ . '/../../database/migrations');
$this->mergeConfigFrom(__DIR__ . '/../../config/image.php', 'image');
$this->app->register(ImageServiceProvider::class);
$this->app->register(ImageOptimizerServiceProvider::class);
$this->loadRoutes();
if ($this->app->runningInConsole()) {
$this->publishes([
// __DIR__ . '/../../config/synchronize.php' => base_path('config/synchronize.php')
]);
}
}
public function loadRoutes()
{
$this->app->get('images/upload', [
'as' => 'uploadImage', 'uses' => '\Meoran\Images\Http\Controllers\ImagesController@upload'
]);
$this->app->get('images/{template}/{filename}', [
'as' => 'getPicture', 'uses' => '\Meoran\Images\Http\Controllers\ImagesController@get'
]);
}
}

18
src/Templates/Large.php Executable file
View File

@@ -0,0 +1,18 @@
<?php
namespace Meoran\Images\Templates;
use Intervention\Image\Constraint;
use Intervention\Image\Filters\FilterInterface;
use Intervention\Image\Image;
class Large implements FilterInterface
{
public function applyFilter(Image $image)
{
return $image->resize(1920, null, function (Constraint $constraint) {
$constraint->upsize();
$constraint->aspectRatio();
});
}
}

18
src/Templates/Medium.php Executable file
View File

@@ -0,0 +1,18 @@
<?php
namespace Meoran\Images\Templates;
use Intervention\Image\Constraint;
use Intervention\Image\Filters\FilterInterface;
use Intervention\Image\Image;
class Medium implements FilterInterface
{
public function applyFilter(Image $image)
{
return $image->resize(240, null, function (Constraint $constraint) {
$constraint->upsize();
$constraint->aspectRatio();
});
}
}

18
src/Templates/Small.php Executable file
View File

@@ -0,0 +1,18 @@
<?php
namespace Meoran\Images\Templates;
use Intervention\Image\Constraint;
use Intervention\Image\Filters\FilterInterface;
use Intervention\Image\Image;
class Small implements FilterInterface
{
public function applyFilter(Image $image)
{
return $image->resize(120, null, function (Constraint $constraint) {
$constraint->upsize();
$constraint->aspectRatio();
});
}
}

14
src/functions.php Executable file
View File

@@ -0,0 +1,14 @@
<?php
if (!function_exists('config_path')) {
/**
* Get the configuration path.
*
* @param string $path
* @return string
*/
function config_path($path = '')
{
return app()->basePath() . '/config' . ($path ? '/' . $path : $path);
}
}