210 lines
6.2 KiB
PHP
210 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Concerns;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Facades\Bus;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
use Spatie\MediaLibrary\Conversions\ConversionCollection;
|
|
use Spatie\MediaLibrary\Conversions\Jobs\PerformConversionsJob;
|
|
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
|
|
|
trait RegistersMedia
|
|
{
|
|
private function registerMediaFromBase64(
|
|
Model $model,
|
|
string $base64Data,
|
|
string $collectionName,
|
|
string $folder,
|
|
): void {
|
|
$dataUrl = $base64Data;
|
|
$mime = 'image/jpeg';
|
|
|
|
if (preg_match('/^data:(.+?);base64,/', $dataUrl, $matches)) {
|
|
$mime = $matches[1];
|
|
$dataUrl = preg_replace('/^data:.+?;base64,/', '', $dataUrl);
|
|
}
|
|
|
|
$binary = base64_decode($dataUrl, true);
|
|
|
|
if ($binary === false) {
|
|
return;
|
|
}
|
|
|
|
$extension = match ($mime) {
|
|
'image/png' => 'png',
|
|
'image/webp' => 'webp',
|
|
'image/gif' => 'gif',
|
|
default => 'jpg',
|
|
};
|
|
|
|
$date = now()->format('Y/m/d');
|
|
$uuid = Str::uuid();
|
|
$key = "{$folder}/{$date}/{$uuid}/photo.{$extension}";
|
|
|
|
Storage::disk('s3')->put($key, $binary, [
|
|
'ContentType' => $mime,
|
|
'ACL' => 'public-read',
|
|
]);
|
|
|
|
$this->registerMedia(
|
|
model: $model,
|
|
s3Key: $key,
|
|
collectionName: $collectionName,
|
|
mimeType: $mime,
|
|
fileSize: strlen($binary),
|
|
orderColumn: 1,
|
|
);
|
|
}
|
|
|
|
private function registerMedia(
|
|
Model $model,
|
|
string $s3Key,
|
|
string $collectionName,
|
|
?int $fileSize = null,
|
|
?string $mimeType = null,
|
|
?int $orderColumn = null,
|
|
?string $name = null,
|
|
): void {
|
|
$fileName = pathinfo($s3Key, PATHINFO_BASENAME);
|
|
|
|
$media = Media::create([
|
|
'model_type' => $model->getMorphClass(),
|
|
'model_id' => $model->id,
|
|
'uuid' => Str::uuid(),
|
|
'collection_name' => $collectionName,
|
|
'name' => $name ?? pathinfo($s3Key, PATHINFO_FILENAME),
|
|
'file_name' => $fileName,
|
|
'mime_type' => $mimeType ?? 'image/jpeg',
|
|
'disk' => 's3',
|
|
'conversions_disk' => 's3',
|
|
'size' => $fileSize ?? 0,
|
|
'manipulations' => [],
|
|
'custom_properties' => ['s3_key' => $s3Key],
|
|
'generated_conversions' => [],
|
|
'responsive_images' => [],
|
|
'order_column' => $orderColumn ?? 1,
|
|
]);
|
|
|
|
$this->generateMediaConversions($media);
|
|
}
|
|
|
|
private function generateMediaConversions(Media $media): void
|
|
{
|
|
$model = $media->model;
|
|
|
|
if (! $model || ! method_exists($model, 'registerMediaConversions')) {
|
|
return;
|
|
}
|
|
|
|
$conversions = ConversionCollection::createForMedia($media);
|
|
|
|
if ($conversions->isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
Bus::dispatch(new PerformConversionsJob($conversions, $media));
|
|
}
|
|
|
|
private function syncPhoto(Model $model, array $data, string $collectionName = 'photos'): void
|
|
{
|
|
if (! array_key_exists('photo_key', $data)) {
|
|
return;
|
|
}
|
|
|
|
$currentKey = $model->getFirstMedia($collectionName)?->getCustomProperty('s3_key');
|
|
|
|
if ($data['photo_key'] === $currentKey) {
|
|
return;
|
|
}
|
|
|
|
$model->clearMediaCollection($collectionName);
|
|
|
|
if (! empty($data['photo_key'])) {
|
|
$this->registerMedia(
|
|
model: $model,
|
|
s3Key: $data['photo_key'],
|
|
collectionName: $collectionName,
|
|
orderColumn: 1,
|
|
);
|
|
}
|
|
}
|
|
|
|
private function syncReceipt(Model $model, ?string $newKey, string $collectionName = 'receipts', string $cachePrefix = 'receipt', ?int $fileSize = null, ?string $fileMimeType = null): void
|
|
{
|
|
$currentMedia = $model->getFirstMedia($collectionName);
|
|
$currentKey = $currentMedia?->getCustomProperty('s3_key');
|
|
|
|
if ($newKey === $currentKey) {
|
|
return;
|
|
}
|
|
|
|
if ($currentMedia) {
|
|
Cache::forget("{$cachePrefix}_{$currentMedia->id}");
|
|
}
|
|
|
|
$model->clearMediaCollection($collectionName);
|
|
|
|
if (! empty($newKey)) {
|
|
$this->registerMedia(
|
|
model: $model,
|
|
s3Key: $newKey,
|
|
collectionName: $collectionName,
|
|
fileSize: $fileSize,
|
|
mimeType: $fileMimeType,
|
|
);
|
|
}
|
|
}
|
|
|
|
private function registerPhoto(Model $model, string $s3Key, string $collectionName = 'images'): void
|
|
{
|
|
$this->registerMedia(
|
|
model: $model,
|
|
s3Key: $s3Key,
|
|
collectionName: $collectionName,
|
|
orderColumn: 1,
|
|
);
|
|
}
|
|
|
|
public function registerPhotos(Model $model, array $photoKeys, string $collectionName = 'images'): void
|
|
{
|
|
foreach ($photoKeys as $order => $s3Key) {
|
|
$this->registerMedia(
|
|
model: $model,
|
|
s3Key: $s3Key,
|
|
collectionName: $collectionName,
|
|
orderColumn: $order + 1,
|
|
);
|
|
}
|
|
}
|
|
|
|
public function syncPhotos(Model $model, array $photoKeys, string $collectionName = 'images'): void
|
|
{
|
|
$existingMedia = $model->getMedia($collectionName);
|
|
$existingKeys = $existingMedia
|
|
->map(fn (Media $m) => $m->getCustomProperty('s3_key') ?? $m->file_name)
|
|
->toArray();
|
|
|
|
foreach ($existingMedia as $media) {
|
|
$key = $media->getCustomProperty('s3_key') ?? $media->file_name;
|
|
|
|
if (! in_array($key, $photoKeys)) {
|
|
$media->delete();
|
|
}
|
|
}
|
|
|
|
$newKeys = array_values(array_diff($photoKeys, $existingKeys));
|
|
|
|
$this->registerPhotos($model, $newKeys, $collectionName);
|
|
}
|
|
|
|
public function getTemporaryUrls(Model $model, string $collectionName = 'images'): array
|
|
{
|
|
$media = $model->getMedia($collectionName);
|
|
|
|
return $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
|
}
|
|
}
|