Skip to content

Commit

Permalink
support deleting files and refacto jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
QuentinGab committed Nov 25, 2023
1 parent 504d2c4 commit 944ba86
Show file tree
Hide file tree
Showing 10 changed files with 353 additions and 21 deletions.
6 changes: 3 additions & 3 deletions database/factories/MediaFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function definition()
'name' => 'empty',
'file_name' => 'empty.jpg',
'size' => 10,
'path' => "/uuid/empty.jpg",
'path' => '/uuid/empty.jpg',
'type' => MediaType::Image,
'collection_name' => config('media.default_collection_name'),
'disk' => config('media.disk'),
Expand All @@ -39,13 +39,13 @@ public static function generatedConversion()
name: 'poster',
path: '/poster/poster.png',
disk: config('media.disk'),
conversions: collect([
generated_conversions: collect([
'480p' => new GeneratedConversion(
state: 'success',
type: MediaType::Image,
file_name: 'poster-480p.png',
name: 'poster-480p',
path: '/poster/conversions/480p/poster-480p.png',
path: '/poster/generated_conversions/480p/poster-480p.png',
disk: config('media.disk'),
),
])
Expand Down
34 changes: 31 additions & 3 deletions src/Casts/GeneratedConversion.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@

namespace Finller\LaravelMedia\Casts;

use Carbon\Carbon;
use Finller\LaravelMedia\Enums\MediaType;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File as SupportFile;
use Illuminate\Support\Facades\Storage;

/**
* @property null|Collection<string, GeneratedConversion> $conversions
* @property null|Collection<string, GeneratedConversion> $generated_conversions
*/
class GeneratedConversion implements Arrayable
{
public Carbon $created_at;

public Carbon $state_set_at;

public function __construct(
public string $file_name,
public string $name,
Expand All @@ -26,8 +33,12 @@ public function __construct(
public ?float $aspect_ratio = null,
public ?string $average_color = null,
public ?string $state = null,
public Collection $conversions = new Collection()
public Collection $generated_conversions = new Collection(),
Carbon $created_at = null,
Carbon $state_set_at = null,
) {
$this->created_at = $created_at ?? now();
$this->state_set_at = $state_set_at ?? now();
}

public static function make(array $attributes): self
Expand All @@ -36,6 +47,7 @@ public static function make(array $attributes): self
file_name: Arr::get($attributes, 'file_name'),
name: Arr::get($attributes, 'name'),
state: Arr::get($attributes, 'state'),
state_set_at: Carbon::parse(Arr::get($attributes, 'state_set_at', now())),
type: ($type = Arr::get($attributes, 'type')) ? MediaType::from($type) : MediaType::Other,
disk: Arr::get($attributes, 'disk'),
path: Arr::get($attributes, 'path'),
Expand All @@ -46,10 +58,26 @@ public static function make(array $attributes): self
width: Arr::get($attributes, 'width'),
aspect_ratio: Arr::get($attributes, 'aspect_ratio'),
average_color: Arr::get($attributes, 'average_color'),
conversions: collect(Arr::get($attributes, 'conversions', []))->map(fn ($item) => self::make($item)),
generated_conversions: collect(Arr::get($attributes, 'generated_conversions', []))->map(fn ($item) => self::make($item)),
created_at: Carbon::parse(Arr::get($attributes, 'created_at', now())),
);
}

function delete(): static
{
if ($this->path) {
Storage::disk($this->disk)->deleteDirectory(
SupportFile::dirname($this->path)
);
$this->path = null;
}

$this->generated_conversions->each(fn (self $generatedConversion) => $generatedConversion->delete());
$this->generated_conversions = collect();

return $this;
}

public function toArray(): array
{
return array_map(
Expand Down
34 changes: 34 additions & 0 deletions src/Jobs/ConversionJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Finller\LaravelMedia\Jobs;

use Finller\LaravelMedia\Media;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Spatie\TemporaryDirectory\TemporaryDirectory;

class ConversionJob implements ShouldBeUnique, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public TemporaryDirectory $temporaryDirectory;

public function __construct(public Media $media, public string $conversion)
{
$this->temporaryDirectory = (new TemporaryDirectory())->deleteWhenDestroyed()->create();
}

public function uniqueId()
{
return "{$this->media->id}:{$this->conversion}";
}

public function handle()
{
//
}
}
34 changes: 34 additions & 0 deletions src/Jobs/OptimizedImageConversionJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Finller\LaravelMedia\Jobs;

use Finller\LaravelMedia\Media;
use Spatie\Image\Image;
use Spatie\Image\Manipulations;

class OptimizedImageConversionJob extends ConversionJob
{
public function __construct(public Media $media, public string $conversion, public ?int $width = null, public ?int $height = null)
{
parent::__construct($media, $conversion);
}

public function handle()
{
$temporaryFilePath = $this->temporaryDirectory->path('file');

$this->media->copyFileTo($temporaryFilePath);

Image::load($temporaryFilePath)
->manipulate(function (Manipulations $manipulations) {
if ($this->width || $this->height) {
$manipulations->fit(Manipulations::FIT_MAX, $this->width, $this->height);
}

$manipulations->optimize();
})
->save();

$this->media->storeConversion($temporaryFilePath, $this->conversion, $this->media->name);
}
}
79 changes: 72 additions & 7 deletions src/Media.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,23 @@ class Media extends Model
'generated_conversions' => GeneratedConversions::class,
];

public static function booted()
{
static::deleted(function (Media $media) {
$media->deleteDirectory();
$media->deleteGeneratedConversions();
});
}


public function model(): MorphTo
{
return $this->morphTo();
}

public function getConversionKey(string $conversion): string
{
return str_replace('.', '.conversions.', $conversion);
return str_replace('.', '.generated_conversions.', $conversion);
}

public function getGeneratedConversion(string $conversion): ?GeneratedConversion
Expand Down Expand Up @@ -102,12 +111,27 @@ protected function generatePath(): string
protected function generateBasePath(string $conversion = null): string
{
if ($conversion) {
return "/{$this->uuid}/conversions/" . str_replace('.', '/', $this->getConversionKey($conversion)) . '/';
return "/{$this->uuid}/generated_conversions/" . str_replace('.', '/', $this->getConversionKey($conversion)) . '/';
}

return "/{$this->uuid}/";
}

/**
* @return null|resource
*/
public function readStream()
{
return Storage::disk($this->disk)->readStream($this->path);
}

public function copyFileTo(string $path): static
{
file_put_contents($path, $this->readStream());

return $this;
}

/**
* Retreive the url of a conversion or nested conversion
* Ex: $media->getUrl('poster.480p')
Expand All @@ -117,17 +141,33 @@ public function getUrl(string $conversion = null)
return Storage::disk($this->disk)->url($this->getPath($conversion));
}

public function addGeneratedConversion(string $name, GeneratedConversion $generatedConversion): static
public function putGeneratedConversion(string $conversion, GeneratedConversion $generatedConversion): static
{
$genealogy = explode('.', $conversion);

if (count($genealogy) > 1) {
$child = Arr::last($genealogy);
$parents = implode('.', array_slice($genealogy, 0, count($genealogy) - 1));
$conversion = $this->getGeneratedConversion($parents);
$conversion->generated_conversions->put($child, $generatedConversion);
} else {
$this->generated_conversions->put($conversion, $generatedConversion);
}

return $this;
}

function forgetGeneratedConversion(string $conversion): static
{
$genealogy = explode('.', $name);
$genealogy = explode('.', $conversion);

if (count($genealogy) > 1) {
$child = Arr::last($genealogy);
$parents = implode('.', array_slice($genealogy, 0, count($genealogy) - 1));
$conversion = $this->getGeneratedConversion($parents);
$conversion->conversions->put($child, $generatedConversion);
$conversion->generated_conversions->forget($child);
} else {
$this->generated_conversions->put($name, $generatedConversion);
$this->generated_conversions->forget($conversion);
}

return $this;
Expand Down Expand Up @@ -225,7 +265,7 @@ public function storeConversion(
size: $file->getSize(),
);

$this->addGeneratedConversion($conversion, $generatedConversion);
$this->putGeneratedConversion($conversion, $generatedConversion);

Storage::disk($generatedConversion->disk)->putFileAs(
SupportFile::dirname($generatedConversion->path),
Expand All @@ -237,6 +277,31 @@ public function storeConversion(

return $this;
}


function deleteDirectory(): static
{
Storage::disk($this->disk)->deleteDirectory(
SupportFile::dirname($this->path)
);
return $this;
}

function deleteGeneratedConversion(string $converion): static
{
$this->getGeneratedConversion($converion)?->delete();
$this->forgetGeneratedConversion($converion);
$this->save();
return $this;
}

function deleteGeneratedConversions(): static
{
$this->generated_conversions->each(fn (GeneratedConversion $generatedConversion) => $generatedConversion->delete());
$this->generated_conversions = collect();
$this->save();
return $this;
}
}

// media/uuid
Expand Down
17 changes: 17 additions & 0 deletions src/MediaCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Finller\LaravelMedia;

use Illuminate\Support\Collection;

/**
* @property Collection<int, MediaConversion> $conversions
*/
class MediaCollection
{
public function __construct(
public ?array $acceptedMimeTypes = null,
public Collection $conversions = new Collection()
) {
}
}
14 changes: 14 additions & 0 deletions src/MediaConversion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Finller\LaravelMedia;

use Finller\LaravelMedia\Jobs\ConversionJob;

class MediaConversion
{
public function __construct(
public string $name,
public string|ConversionJob $job
) {
}
}
40 changes: 40 additions & 0 deletions src/Traits/HasMedia.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

namespace Finller\LaravelMedia\Traits;

use Finller\LaravelMedia\Jobs\ConversionJob;
use Finller\LaravelMedia\Media;
use Finller\LaravelMedia\MediaCollection;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;

/**
Expand All @@ -15,8 +19,44 @@ public function media(): MorphMany
return $this->morphMany(config('media-library.media_model'), 'model');
}

/**
* @return Collection<string, MediaCollection>
*/
public function getMediaCollections(): Collection
{
return collect([]);
}

public function addMedia(string|UploadedFile $file, string $collection_name = null): static
{
$collection_name ??= config('media.default_collection_name');

$media = new Media();

$media->storeFile($file);

$this->dispatchConversions($media, $collection_name);

return $this;
}

public function dispatchConversions(Media $media, string $collection_name): static
{
$collection = $this->getMediaCollections()->get($collection_name);

if (! $collection) {
return $this;
}

foreach ($collection->conversions as $conversion) {
if ($conversion->job instanceof ConversionJob) {
dispatch($conversion->job);
} else {
$job = $conversion->job;
dispatch(new $job($media, $conversion->name));
}
}

return $this;
}
}
Loading

0 comments on commit 944ba86

Please sign in to comment.