Compare commits

...

8 Commits

Author SHA1 Message Date
philipp lang 4a87b83b5a Add pathinfo information to default Properties 2024-10-30 15:25:43 +01:00
philipp lang 09919a1c29 Add heic support 2024-04-30 14:13:21 +02:00
philipp lang 820a725517 Lint 2024-01-02 01:28:49 +01:00
philipp lang 2d39816954 Lint 2024-01-02 01:28:16 +01:00
philipp lang 7e8f762885 Lint 2024-01-02 01:27:56 +01:00
philipp lang 9c33c8f128 Update tests 2024-01-02 00:41:22 +01:00
philipp lang cfb38ed792 Update README 2024-01-02 00:22:42 +01:00
Philipp Lang 2473c7c55b Add max width to upload 2023-05-02 14:23:25 +02:00
10 changed files with 3144 additions and 1035 deletions

28
README.md Normal file
View File

@ -0,0 +1,28 @@
# Laravel Medialibrary Helper
This package creates routes for the popular Medialibrary Package from Spatie ().
## Available methods
In RegisterMediaCollections, you have the following methods available:
You can set a filename by default for the file. This accepts the associated Model, as well as the original filename. You should return the new name of the file with the extension (e.g. disc.jpg).
```
forceFileName(fn ($model, $path) => Str::slug($path))
```
You can set a max width (in Pixels) for images. This will resize the image BEFORE any normal Medialibrary conversions take place.
```
maxWidth(fn () => 2500)
```
You can call whatever you want after an image has been added, modified or deleted.
```
->after(function ($model) {
....
})
```

View File

@ -16,6 +16,7 @@
}
],
"require": {
"ext-imagick": ">=3.6.0",
"spatie/laravel-medialibrary": "^10.7",
"laravel/framework": "^9.50",
"spatie/laravel-data": "^3.1",
@ -35,5 +36,12 @@
"allow-plugins": {
"pestphp/pest-plugin": true
}
},
"extra": {
"laravel": {
"providers": [
"Zoomyboy\\MedialibraryHelper\\ServiceProvider"
]
}
}
}

3957
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,8 @@ class CollectionExtension
{
public function boot(): void
{
MediaCollection::mixin(new class() {
MediaCollection::mixin(new class()
{
public function forceFileName()
{
return fn ($callback) => $this->registerCustomCallback('forceFileName', $callback);
@ -49,6 +50,11 @@ class CollectionExtension
return fn ($callback) => $this->registerCustomCallback('withFallback', $callback);
}
public function maxWidth()
{
return fn ($callback) => $this->registerCustomCallback('maxWidth', $callback);
}
public function runCallback()
{
return function (string $callback, ...$parameters) {
@ -76,11 +82,12 @@ class CollectionExtension
}
$this->customCallbacks = collect([
'forceFileName' => fn ($model, $name) => $name,
'maxWidth' => fn ($size) => null,
'stored' => fn ($event) => true,
'after' => fn ($event) => true,
'destroyed' => fn ($event) => true,
'storing' => fn ($adder, $name) => $adder,
'withDefaultProperties' => fn ($path) => [],
'withDefaultProperties' => fn ($path, $pathinfo) => [],
'withPropertyValidation' => fn ($path) => [],
'withFallback' => fn ($parent) => null,
]);

View File

@ -2,13 +2,17 @@
namespace Zoomyboy\MedialibraryHelper;
use Imagick;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Spatie\Image\Image;
use Spatie\LaravelData\DataCollection;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\MediaCollections\Exceptions\InvalidBase64Data;
use Spatie\MediaLibrary\MediaCollections\FileAdder;
use Spatie\MediaLibrary\MediaCollections\MediaCollection;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
@ -46,11 +50,11 @@ class MediaController
$pathinfo = pathinfo($c['name']);
$basename = $collection->runCallback('forceFileName', $model, $pathinfo['filename']);
$path = $basename . '.' . $pathinfo['extension'];
$adder = $model
->addMediaFromBase64($c['content'])
$adder = $this->fileAdderFromData($model, $c['content'], $collection)
->usingName($basename)
->usingFileName($path)
->withCustomProperties($collection->runCallback('withDefaultProperties', $path));
->withCustomProperties($collection->runCallback('withDefaultProperties', $path, $pathinfo));
return tap(
$collection->runCallback('storing', $adder, $path)->toMediaCollection($collection->name),
@ -133,4 +137,42 @@ class MediaController
return $model;
}
protected function fileAdderFromData($model, $data, $collection): FileAdder
{
$maxWidth = $collection->runCallback('maxWidth', 9);
if (str_contains($data, ';base64')) {
[$_, $data] = explode(';', $data);
[$_, $data] = explode(',', $data);
}
// strict mode filters for non-base64 alphabet characters
$binaryData = base64_decode($data, true);
if (false === $binaryData) {
throw InvalidBase64Data::create();
}
// decoding and then reencoding should not change the data
if (base64_encode($binaryData) !== $data) {
throw InvalidBase64Data::create();
}
$tmpFile = tempnam(sys_get_temp_dir(), 'media-library');
file_put_contents($tmpFile, $binaryData);
$i = (new Imagick());
$i->readImage($tmpFile);
if ($i->getImageFormat() === 'HEIC') {
$i->setFormat('jpg');
$i->writeImage($tmpFile);
}
if (null !== $maxWidth && 'image/jpeg' === mime_content_type($tmpFile)) {
Image::load($tmpFile)->width($maxWidth)->save();
}
return $model->addMedia($tmpFile);
}
}

View File

@ -1,44 +0,0 @@
<?php
namespace Zoomyboy\MedialibraryHelper\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Zoomyboy\MedialibraryHelper\Tests\TestCase;
class MiddlewareTest extends TestCase
{
use RefreshDatabase;
public function testItReturns401WhenNotLoggedIn(): void
{
$this->registerModel();
$post = $this->newPost();
$response = $this->postJson('/mediaupload', [
'model' => 'post',
'id' => $post->id,
'collection' => 'defaultSingleFile',
'content' => base64_encode($this->pdfFile()->getContent()),
'name' => 'beispiel bild.jpg',
]);
$response->assertStatus(401);
}
public function testItReturns401WhenDestroying(): void
{
$this->registerModel();
$post = $this->newPost();
$media = $post->addMedia($this->pdfFile()->getPathname())->toMediaCollection('defaultSingleFile');
$response = $this->deleteJson("/mediaupload/{$media->id}");
$response->assertStatus(401);
}
protected function defineEnvironment($app)
{
$app['config']->set('media-library.middleware', ['web', 'auth:web']);
}
}

View File

@ -35,6 +35,41 @@ test('it uploads a single file to a single file collection', function () {
$response->assertJsonMissingPath('model_id');
});
test('it uploads heig image', function () {
$this->auth()->registerModel();
$post = $this->newPost();
$content = base64_encode($this->getFile('heic.jpg', 'heic.jpg')->getContent());
$this->postJson('/mediaupload', [
'model' => 'post',
'id' => $post->id,
'collection' => 'conversionsWithDefault',
'payload' => [
'content' => $content,
'name' => 'beispiel bild.jpg',
],
])->assertStatus(201);
});
test('it uploads a single image to a single file collection', function () {
$this->auth()->registerModel();
$post = $this->newPost();
$content = base64_encode($this->jpgFile()->getContent());
$response = $this->postJson('/mediaupload', [
'model' => 'post',
'id' => $post->id,
'collection' => 'defaultSingleFile',
'payload' => [
'content' => $content,
'name' => 'beispiel bild.jpg',
],
]);
$response->assertStatus(201);
$this->assertCount(1, $post->getMedia('defaultSingleFile'));
});
test('it forces a filename for a single collection', function () {
Carbon::setTestNow(Carbon::parse('2023-04-04 00:00:00'));
$this->auth()->registerModel();

View File

@ -20,7 +20,7 @@ class Post extends Model implements HasMedia
public function registerMediaCollections(): void
{
$this->addMediaCollection('defaultSingleFile')->singleFile();
$this->addMediaCollection('defaultSingleFile')->maxWidth(fn () => 250)->singleFile();
$this->addMediaCollection('conversionsWithDefault')
->singleFile()
@ -56,7 +56,7 @@ class Post extends Model implements HasMedia
Event::dispatch(new MediaStored($media));
});
$this->addMediaCollection('multipleProperties')->singleFile()->withDefaultProperties(fn ($path) => [
$this->addMediaCollection('multipleProperties')->singleFile()->withDefaultProperties(fn ($path, $pathinfo) => [
'test' => Str::camel($path),
])->withPropertyValidation(fn ($path) => [
'test' => 'string|max:10',

BIN
tests/stubs/heic.jpg Normal file

Binary file not shown.