97 lines
2.5 KiB
PHP
97 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
|
|
|
class CleanupOrphanedMediaJob implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
public int $tries = 3;
|
|
|
|
public int $chunkSize = 100;
|
|
|
|
public function handle(): void
|
|
{
|
|
$orphanedMedia = $this->getOrphanedMedia();
|
|
|
|
if ($orphanedMedia->isEmpty()) {
|
|
Log::info('CleanupOrphanedMediaJob: Tidak ada media orphaned.');
|
|
|
|
return;
|
|
}
|
|
|
|
$totalDeleted = 0;
|
|
|
|
$orphanedMedia->each(function (Media $media) use (&$totalDeleted) {
|
|
$this->deleteMedia($media);
|
|
$totalDeleted++;
|
|
});
|
|
|
|
Log::info("CleanupOrphanedMediaJob: Berhasil hapus {$totalDeleted} media orphaned.");
|
|
}
|
|
|
|
private function getOrphanedMedia()
|
|
{
|
|
$allMedia = Media::select(['id', 'model_type', 'model_id', 'file_name', 'custom_properties', 'disk'])
|
|
->get()
|
|
->groupBy(fn (Media $m) => $m->model_type.'|'.$m->model_id);
|
|
|
|
$orphanedIds = [];
|
|
|
|
foreach ($allMedia as $key => $mediaItems) {
|
|
[$modelType, $modelId] = explode('|', $key);
|
|
|
|
if ($this->isOrphaned($modelType, (int) $modelId)) {
|
|
foreach ($mediaItems as $media) {
|
|
$orphanedIds[] = $media->id;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($orphanedIds)) {
|
|
return collect();
|
|
}
|
|
|
|
return Media::whereIn('id', $orphanedIds)->get();
|
|
}
|
|
|
|
private function isOrphaned(string $modelType, int $modelId): bool
|
|
{
|
|
if (! class_exists($modelType)) {
|
|
return true;
|
|
}
|
|
|
|
$model = $modelType::withTrashed()->find($modelId);
|
|
|
|
if (! $model) {
|
|
return true;
|
|
}
|
|
|
|
if (method_exists($model, 'trashed') && $model->trashed()) {
|
|
return $model->deleted_at->lt(now()->subMonth());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function deleteMedia(Media $media): void
|
|
{
|
|
$s3Key = $media->getCustomProperty('s3_key');
|
|
|
|
if ($s3Key && Storage::disk($media->disk)->exists($s3Key)) {
|
|
Storage::disk($media->disk)->delete($s3Key);
|
|
}
|
|
|
|
$media->forceDelete();
|
|
}
|
|
}
|