feat: remove unused media collection clearing in destroy methods and add CleanupOrphanedMediaJob for orphaned media management
This commit is contained in:
parent
e1a0d25c3c
commit
1f41f04199
96
app/Jobs/CleanupOrphanedMediaJob.php
Normal file
96
app/Jobs/CleanupOrphanedMediaJob.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -168,8 +168,6 @@ public function destroy(CashTransaction $transaction): bool
|
|||||||
Cache::forget("cash_transaction_receipt_{$media->id}");
|
Cache::forget("cash_transaction_receipt_{$media->id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
$transaction->clearMediaCollection('photos');
|
|
||||||
|
|
||||||
$deleted = $transaction->delete();
|
$deleted = $transaction->delete();
|
||||||
|
|
||||||
if ($deleted) {
|
if ($deleted) {
|
||||||
|
|||||||
@ -130,8 +130,6 @@ public function destroy(Expense $expense): bool
|
|||||||
Cache::forget("expense_receipt_{$media->id}");
|
Cache::forget("expense_receipt_{$media->id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
$expense->clearMediaCollection('photos');
|
|
||||||
|
|
||||||
$deleted = $expense->delete();
|
$deleted = $expense->delete();
|
||||||
|
|
||||||
if ($deleted) {
|
if ($deleted) {
|
||||||
|
|||||||
@ -357,7 +357,6 @@ public function destroy(Cutting $cutting): bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$cutting->clearMediaCollection('images');
|
|
||||||
$cutting->cuttingResults()->delete();
|
$cutting->cuttingResults()->delete();
|
||||||
$cutting->cuttingMaterials()->delete();
|
$cutting->cuttingMaterials()->delete();
|
||||||
$cutting->cuttingMaterialCombinations()->delete();
|
$cutting->cuttingMaterialCombinations()->delete();
|
||||||
|
|||||||
@ -480,7 +480,6 @@ public function destroy(Purchase $purchase): bool
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$purchase->clearMediaCollection('photos');
|
|
||||||
$purchase->purchaseItems()->delete();
|
$purchase->purchaseItems()->delete();
|
||||||
$purchase->delete();
|
$purchase->delete();
|
||||||
|
|
||||||
|
|||||||
@ -144,7 +144,6 @@ public function destroy(Restock $restock): bool
|
|||||||
});
|
});
|
||||||
|
|
||||||
$restock->restockItems()->delete();
|
$restock->restockItems()->delete();
|
||||||
$restock->clearMediaCollection('photos');
|
|
||||||
$restock->delete();
|
$restock->delete();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -299,7 +299,6 @@ public function destroy(Order $order): bool
|
|||||||
});
|
});
|
||||||
|
|
||||||
$order->orderItems()->delete();
|
$order->orderItems()->delete();
|
||||||
$order->clearMediaCollection('photos');
|
|
||||||
$order->delete();
|
$order->delete();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -404,7 +404,6 @@ public function destroy(Product $product): bool
|
|||||||
$result = DB::transaction(function () use ($product) {
|
$result = DB::transaction(function () use ($product) {
|
||||||
$product->productVariants->each(function (ProductVariant $variant) {
|
$product->productVariants->each(function (ProductVariant $variant) {
|
||||||
$variant->productPrices()->delete();
|
$variant->productPrices()->delete();
|
||||||
$variant->clearMediaCollection('images');
|
|
||||||
$variant->delete();
|
$variant->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -156,7 +156,6 @@ public function destroy(Product $product, ProductVariant $variant): bool
|
|||||||
|
|
||||||
$result = DB::transaction(function () use ($variant) {
|
$result = DB::transaction(function () use ($variant) {
|
||||||
$variant->productPrices()->delete();
|
$variant->productPrices()->delete();
|
||||||
$variant->clearMediaCollection('images');
|
|
||||||
|
|
||||||
return $variant->delete();
|
return $variant->delete();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -213,7 +213,6 @@ public function destroy(RawMaterial $rawMaterial): bool
|
|||||||
{
|
{
|
||||||
return DB::transaction(function () use ($rawMaterial) {
|
return DB::transaction(function () use ($rawMaterial) {
|
||||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||||
$price->clearMediaCollection('images');
|
|
||||||
$price->delete();
|
$price->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -93,8 +93,6 @@ public function update(RawMaterialPrice $variant, array $data): RawMaterialPrice
|
|||||||
public function destroy(RawMaterial $rawMaterial, RawMaterialPrice $variant): bool
|
public function destroy(RawMaterial $rawMaterial, RawMaterialPrice $variant): bool
|
||||||
{
|
{
|
||||||
$result = DB::transaction(function () use ($variant) {
|
$result = DB::transaction(function () use ($variant) {
|
||||||
$variant->clearMediaCollection('images');
|
|
||||||
|
|
||||||
return $variant->delete();
|
return $variant->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use App\Console\Commands\GeneratePayrollCommand;
|
use App\Console\Commands\GeneratePayrollCommand;
|
||||||
use App\Jobs\CheckAttendancePenaltiesJob;
|
use App\Jobs\CheckAttendancePenaltiesJob;
|
||||||
|
use App\Jobs\CleanupOrphanedMediaJob;
|
||||||
use Illuminate\Support\Facades\Schedule;
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
|
||||||
Schedule::command(GeneratePayrollCommand::class)->monthlyOn(1, '00:00');
|
Schedule::command(GeneratePayrollCommand::class)->monthlyOn(1, '00:00');
|
||||||
Schedule::job(new CheckAttendancePenaltiesJob)->dailyAt('00:00');
|
Schedule::job(new CheckAttendancePenaltiesJob)->dailyAt('00:00');
|
||||||
|
Schedule::job(new CleanupOrphanedMediaJob)->monthlyOn(1, '01:00');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user