images: press-release-images:regenerate-variants --only=og für den Bestand, Testhelfer eindeutig benannt (Bildkennzeichnung H.1)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-22 10:13:49 +00:00
parent 075d0d931f
commit 70e15d5df5
3 changed files with 135 additions and 5 deletions

View file

@ -0,0 +1,101 @@
<?php
namespace App\Console\Commands;
use App\Models\PressReleaseImage;
use App\Scopes\PortalScope;
use App\Services\Image\ImageService;
use App\Support\ImageCredit;
use Illuminate\Console\Command;
/**
* Bildkennzeichnung H.1, Bestand: OG-Variante mit eingebranntem Nachweis
* für Bilder nachziehen, die noch keine haben (vor Formular v2 hochgeladen
* oder importiert). Quelle ist die größte vorhandene Variante; der Nachweis
* kommt aus der gemeinsamen Auflösung (Foto: … / Quelle: [Firma]).
*/
class RegeneratePressReleaseImageVariants extends Command
{
protected $signature = 'press-release-images:regenerate-variants
{--only=og : Nur diese Variante (derzeit: og)}
{--published : Nur Bilder veröffentlichter Meldungen}
{--force : Auch vorhandene Varianten neu erzeugen}
{--limit=0 : Höchstens so viele Bilder (0 = alle)}
{--execute : Wirklich schreiben (Standard ist ein Trockenlauf)}';
protected $description = 'Erzeugt fehlende OG-Varianten mit eingebranntem Bildnachweis für den Bestand';
public function __construct(private readonly ImageService $imageService)
{
parent::__construct();
}
public function handle(): int
{
if ($this->option('only') !== 'og') {
$this->error('Derzeit wird nur --only=og unterstützt.');
return self::FAILURE;
}
$query = PressReleaseImage::query()
->with(['pressRelease' => fn ($q) => $q->withoutGlobalScope(PortalScope::class)->with('company')])
->orderBy('id');
if ($this->option('published')) {
$query->whereHas('pressRelease', fn ($q) => $q->withoutGlobalScope(PortalScope::class)->where('status', 'published'));
}
if (! $this->option('force')) {
$query->where(function ($q): void {
$q->whereNull('variants')->orWhereNull('variants->og');
});
}
$total = $query->count();
$limit = (int) $this->option('limit');
$execute = (bool) $this->option('execute');
$this->info(($execute ? 'Erzeuge' : 'Trockenlauf:').' OG-Varianten für '.($limit > 0 ? min($limit, $total) : $total).' von '.$total.' Bildern.');
if (! $execute) {
return self::SUCCESS;
}
$done = 0;
$skipped = 0;
$query->chunkById(200, function ($images) use (&$done, &$skipped, $limit): bool {
foreach ($images as $image) {
if ($limit > 0 && $done >= $limit) {
return false;
}
$caption = $image->pressRelease ? ImageCredit::for($image, $image->pressRelease->company)->line() : null;
$path = $this->imageService->regenerateOgVariant(
$image->disk,
$image->variants,
$image->path,
$image->focus_x !== null && $image->focus_y !== null ? ['x' => $image->focus_x, 'y' => $image->focus_y] : null,
(bool) $image->no_crop,
$caption,
);
if ($path === null) {
$skipped++;
continue;
}
$image->forceFill(['variants' => array_merge((array) $image->variants, ['og' => $path])])->saveQuietly();
$done++;
}
return true;
});
$this->info("OG-Varianten erzeugt: {$done}, übersprungen (keine Quelle): {$skipped}.");
return self::SUCCESS;
}
}