Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
71 lines
2.3 KiB
PHP
71 lines
2.3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use App\Models\Media;
|
||
use App\Services\Media\ImageProcessor;
|
||
use Illuminate\Console\Command;
|
||
|
||
/**
|
||
* The safety net, and the way back from a change of settings.
|
||
*
|
||
* Uploads queue their own processing, but a queue that is not running would
|
||
* leave images without dimensions and nobody would notice until the page
|
||
* reflowed. The scheduler runs this every ten minutes so a stalled worker
|
||
* costs a delay rather than a permanently half-done image.
|
||
*
|
||
* `--all` reprocesses everything, which is what you want after changing the
|
||
* widths or adding a format: the media table is derived, so it can always be
|
||
* rebuilt from the files themselves.
|
||
*/
|
||
class ProcessMediaCommand extends Command
|
||
{
|
||
protected $signature = 'media:process
|
||
{--all : Reprocess every image, not only the pending ones}
|
||
{--limit=100 : Maximum number of images to handle in one run}';
|
||
|
||
protected $description = 'Derive dimensions, responsive versions and placeholders for uploaded images';
|
||
|
||
public function handle(ImageProcessor $processor): int
|
||
{
|
||
$media = Media::query()
|
||
->unless($this->option('all'), fn ($q) => $q->pending())
|
||
->orderBy('id')
|
||
->limit(max(1, (int) $this->option('limit')))
|
||
->get();
|
||
|
||
if ($media->isEmpty()) {
|
||
$this->components->info('Nothing to process.');
|
||
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
$failed = 0;
|
||
|
||
foreach ($media as $item) {
|
||
$processor->process($item->refresh());
|
||
|
||
if ($item->refresh()->error) {
|
||
$failed++;
|
||
$this->components->error("{$item->path} — {$item->error}");
|
||
|
||
continue;
|
||
}
|
||
|
||
$this->components->twoColumnDetail(
|
||
$item->path,
|
||
$item->width ? "{$item->width}×{$item->height} · ".count($item->variants ?? []).' versions' : 'no dimensions',
|
||
);
|
||
}
|
||
|
||
$this->newLine();
|
||
$this->components->info("Processed {$media->count()} images, {$failed} failed.");
|
||
|
||
// A failure here is usually a missing file, which is worth a non-zero
|
||
// exit in a deploy script.
|
||
return $failed > 0 ? self::FAILURE : self::SUCCESS;
|
||
}
|
||
}
|