cms/app/Console/Commands/OrphanedMediaWatcher.php
Funky Waddle 37ed997989 feat(cms): initialize Laravel project structure and core CMS files
- Added standard Laravel directory structure and configuration.

- Included Svelte and Tailwind configuration for the admin interface.

- Added core PHPUnit and testing scripts.
2026-04-13 12:48:06 -05:00

117 lines
3.3 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Media;
use App\Models\Page;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class OrphanedMediaWatcher extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'sw:media:cleanup {--dry-run}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Cleanup unreferenced media files and JIT caches.';
/**
* Execute the console command.
*/
public function handle()
{
$this->info('Starting Orphaned Media Watcher...');
$dryRun = $this->option('dry-run');
// 1. Cleanup JIT cache (safe to delete anytime)
$cachePath = storage_path('app/public/media/cache');
if (is_dir($cachePath)) {
$this->info('Cleaning up JIT cache...');
if ($dryRun) {
$this->info('Dry-run: Would delete directory ' . $cachePath);
} else {
File::deleteDirectory($cachePath);
mkdir($cachePath, 0755, true);
}
}
// 2. Identification of orphaned originals
$this->info('Scanning for orphaned media files in database...');
$mediaRecords = Media::all();
$referencedMediaIds = $this->getReferencedMediaIds();
$orphansCount = 0;
foreach ($mediaRecords as $media) {
if (!in_array($media->id, $referencedMediaIds)) {
$orphansCount++;
$this->warn("Orphaned media found: ID {$media->id}, Filename: {$media->filename}");
if ($dryRun) {
$this->info("Dry-run: Would delete media ID {$media->id} and file {$media->path}");
} else {
Storage::disk('public')->delete($media->path);
$media->delete();
$this->info("Deleted media ID {$media->id}");
}
}
}
if ($orphansCount === 0) {
$this->info("\nNo orphaned media files found.");
} else {
$this->info("\nProcessed {$orphansCount} orphaned media files.");
}
$this->info('Media cleanup completed.');
return 0;
}
/**
* Scans all pages for media IDs.
*/
protected function getReferencedMediaIds(): array
{
$ids = [];
$pages = Page::all();
foreach ($pages as $page) {
$content = $page->content; // Array due to cast
if (is_array($content)) {
$ids = array_merge($ids, $this->scanBlocksForMediaIds($content));
}
}
return array_unique($ids);
}
/**
* Recursively scan blocks for media IDs.
*/
protected function scanBlocksForMediaIds(array $blocks): array
{
$ids = [];
foreach ($blocks as $block) {
if (isset($block['type']) && $block['type'] === 'media' && isset($block['media_id'])) {
$ids[] = (int) $block['media_id'];
}
// In case of nested blocks in the future
if (isset($block['children']) && is_array($block['children'])) {
$ids = array_merge($ids, $this->scanBlocksForMediaIds($block['children']));
}
}
return $ids;
}
}