store/app/Services/Media/MediaService.php
Yoga Pangestu 3d00511626
Some checks failed
linter / quality (push) Waiting to run
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
feat: enhance PresignedUploadController to support local uploads and improve S3 integration; add localUpload method for handling uploads when S3 is not the default disk
2026-07-02 22:53:28 +07:00

173 lines
5.1 KiB
PHP

<?php
namespace App\Services\Media;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class MediaService
{
public function syncCollection(
HasMedia $model,
string $collection,
?array $newFiles,
?array $removeIds,
int $maxFiles,
?string $type = null,
bool $required = false,
?string $errorKey = null,
?array $s3Keys = null,
): void {
// Handle removals
if ($maxFiles === 1 && (! empty($newFiles) || ! empty($s3Keys))) {
$model->clearMediaCollection($collection);
} elseif ($removeIds !== null && $removeIds !== []) {
$model->getMedia($collection)
->whereIn('id', $removeIds)
->each->delete();
}
// Determine items to add (S3 keys take priority)
$useS3 = ! empty($s3Keys);
$items = $useS3
? array_values(array_filter($s3Keys))
: array_values(array_filter($newFiles ?? []));
if ($maxFiles === 1) {
$items = array_slice($items, 0, 1);
}
$currentCount = $model->getMedia($collection)->count();
if ($currentCount + count($items) > $maxFiles) {
throw ValidationException::withMessages([
$errorKey ?? $collection => "Maksimal {$maxFiles} gambar per item.",
]);
}
foreach ($items as $item) {
if ($useS3) {
$this->registerS3Key($model, $item, $collection, $type);
} else {
$this->addUploadedFile($model, $item, $collection, $type);
}
}
if ($model instanceof Model) {
$model->unsetRelation('media');
}
if ($required && $model->getMedia($collection)->isEmpty()) {
throw ValidationException::withMessages([
$errorKey ?? $collection => 'Foto wajib diisi.',
]);
}
}
public function addUploadedFile(
HasMedia $model,
UploadedFile $file,
string $collection,
?string $type = null,
): Media {
return $model->addMedia($file)
->withCustomProperties($this->customProperties($model, $type ?? $collection))
->toMediaCollection($collection);
}
/**
* @param HasMedia&InteractsWithMedia $model
*/
public function registerS3Key(
HasMedia $model,
string $s3Key,
string $collection,
?string $type = null,
): Media {
$disk = config('filesystems.default') === 's3' ? 's3' : config('filesystems.default', 'public');
try {
return $model->addMediaFromDisk($s3Key, $disk)
->withCustomProperties($this->customProperties($model, $type ?? $collection))
->toMediaCollection($collection);
} finally {
Storage::disk($disk)->delete($s3Key);
}
}
public function addBase64Image(
HasMedia $model,
string $base64Photo,
string $collection,
?string $type = null,
string $extension = 'jpg',
): Media {
$image = base64_decode(
(string) preg_replace('#^data:image/\w+;base64,#i', '', $base64Photo),
true,
);
if ($image === false) {
throw ValidationException::withMessages([
'photo' => 'Foto tidak valid.',
]);
}
$filename = sprintf('%s.%s', Str::uuid(), $extension);
$tempPath = 'temp/'.$filename;
Storage::disk('local')->put($tempPath, $image);
try {
return $model->addMedia(Storage::disk('local')->path($tempPath))
->usingFileName($filename)
->withCustomProperties($this->customProperties($model, $type ?? $collection))
->toMediaCollection($collection);
} finally {
Storage::disk('local')->delete($tempPath);
}
}
public function replaceSingleFile(
HasMedia $model,
UploadedFile $file,
string $collection,
?string $type = null,
): Media {
$model->clearMediaCollection($collection);
return $this->addUploadedFile($model, $file, $collection, $type);
}
public function replaceSingleS3Key(
HasMedia $model,
string $s3Key,
string $collection,
?string $type = null,
): Media {
$model->clearMediaCollection($collection);
return $this->registerS3Key($model, $s3Key, $collection, $type);
}
private function customProperties(HasMedia $model, ?string $type): array
{
$properties = [
'module' => method_exists($model, 'mediaModuleName')
? $model::mediaModuleName()
: 'media',
];
if ($type !== null && $type !== '') {
$properties['type'] = $type;
}
return $properties;
}
}