99 lines
3.1 KiB
PHP
99 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Services\Cdn\ArtworkCdnPurgeService;
|
|
use App\Services\News\NewsCoverImageService;
|
|
use App\Support\News\NewsCoverImage;
|
|
use Illuminate\Console\Command;
|
|
use cPad\Plugins\News\Models\NewsArticle;
|
|
|
|
final class GenerateNewsCoverThumbnailsCommand extends Command
|
|
{
|
|
protected $signature = 'news:generate-cover-thumbnails {--id=* : Restrict to one or more news article IDs} {--force : Regenerate variants even when they already exist}';
|
|
|
|
protected $description = 'Generate missing responsive cover thumbnails for managed news cover images';
|
|
|
|
public function __construct(
|
|
private readonly NewsCoverImageService $covers,
|
|
private readonly ArtworkCdnPurgeService $cdnPurge,
|
|
)
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
public function handle(): int
|
|
{
|
|
$ids = collect((array) $this->option('id'))
|
|
->map(static fn (mixed $id): int => (int) $id)
|
|
->filter(static fn (int $id): bool => $id > 0)
|
|
->values()
|
|
->all();
|
|
|
|
$force = (bool) $this->option('force');
|
|
|
|
$query = NewsArticle::query()
|
|
->select(['id', 'title', 'cover_image'])
|
|
->whereNotNull('cover_image')
|
|
->where('cover_image', '!=', '');
|
|
|
|
if ($ids !== []) {
|
|
$query->whereIn('id', $ids);
|
|
}
|
|
|
|
$generated = 0;
|
|
$skipped = 0;
|
|
$failed = 0;
|
|
$purged = 0;
|
|
|
|
$query->orderBy('id')->chunkById(100, function ($articles) use (&$generated, &$skipped, &$failed, &$purged, $force): void {
|
|
foreach ($articles as $article) {
|
|
$path = trim((string) $article->cover_image);
|
|
|
|
if (! NewsCoverImage::isManagedPath($path)) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$result = $this->covers->ensureVariants($path, $force);
|
|
} catch (\Throwable $e) {
|
|
$failed++;
|
|
$this->warn(sprintf('Article %d failed: %s', (int) $article->id, $e->getMessage()));
|
|
continue;
|
|
}
|
|
|
|
if (($result['generated'] ?? 0) > 0) {
|
|
$generated++;
|
|
|
|
if ($force && $this->purgeVariantCache($path, (int) $article->id)) {
|
|
$purged++;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
$skipped++;
|
|
}
|
|
});
|
|
|
|
$this->info(sprintf('News cover thumbnail generation complete: generated=%d skipped=%d failed=%d purged=%d', $generated, $skipped, $failed, $purged));
|
|
|
|
return $failed > 0 ? self::FAILURE : self::SUCCESS;
|
|
}
|
|
|
|
private function purgeVariantCache(string $path, int $articleId): bool
|
|
{
|
|
$variantPaths = array_values(array_map(
|
|
static fn (string $variant): string => NewsCoverImage::variantPath($path, $variant),
|
|
array_keys(NewsCoverImage::VARIANTS),
|
|
));
|
|
|
|
return $this->cdnPurge->purgeArtworkObjectPaths($variantPaths, [
|
|
'article_id' => $articleId,
|
|
'reason' => 'news_cover_thumbnails_regenerated',
|
|
]);
|
|
}
|
|
} |