12-05-2026 Frontend dev
This commit is contained in:
parent
405df0a122
commit
5b8bdf4182
779 changed files with 480564 additions and 6241 deletions
235
app/Console/Commands/SyncPressReleaseImages.php
Normal file
235
app/Console/Commands/SyncPressReleaseImages.php
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\Portal;
|
||||
use App\Models\PressReleaseImage;
|
||||
use App\Services\Image\ImageService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SyncPressReleaseImages extends Command
|
||||
{
|
||||
protected $signature = 'legacy:sync-press-release-images
|
||||
{--portal=all : Portal (presseecho|businessportal24|all)}
|
||||
{--dry-run : Nur prüfen, nichts kopieren oder aktualisieren}
|
||||
{--force : Ziel-Dateien erneut überschreiben}
|
||||
{--skip-variants : Varianten nicht regenerieren (nur Datei-Kopie + DB-Update)}
|
||||
{--limit=0 : Maximal N Bilder pro Portal verarbeiten (0 = alle)}';
|
||||
|
||||
protected $description = 'Kopiert referenzierte Legacy-PM-Bilder in den finalen Storage-Pfad, generiert Varianten und aktualisiert press_release_images.';
|
||||
|
||||
public function __construct(private readonly ImageService $imageService)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$portals = $this->selectedPortals();
|
||||
|
||||
if ($portals === []) {
|
||||
$this->error('Ungültiges Portal. Erlaubt: presseecho, businessportal24, all.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$dryRun = (bool) $this->option('dry-run');
|
||||
$force = (bool) $this->option('force');
|
||||
$skipVariants = (bool) $this->option('skip-variants');
|
||||
$limit = max(0, (int) $this->option('limit'));
|
||||
|
||||
$totals = [
|
||||
'referenced' => 0,
|
||||
'copied' => 0,
|
||||
'variants_generated' => 0,
|
||||
'updated' => 0,
|
||||
'already_synced' => 0,
|
||||
'missing' => 0,
|
||||
'unused' => 0,
|
||||
];
|
||||
|
||||
foreach ($portals as $portal) {
|
||||
$stats = $this->syncPortal($portal, $dryRun, $force, $skipVariants, $limit);
|
||||
|
||||
foreach ($totals as $key => $value) {
|
||||
$totals[$key] = $value + $stats[$key];
|
||||
}
|
||||
|
||||
$this->line(sprintf(
|
||||
'%s: referenziert %d, kopiert %d, Varianten %d, DB-Updates %d, bereits synchron %d, fehlend %d, ungenutzt %d',
|
||||
$portal,
|
||||
$stats['referenced'],
|
||||
$stats['copied'],
|
||||
$stats['variants_generated'],
|
||||
$stats['updated'],
|
||||
$stats['already_synced'],
|
||||
$stats['missing'],
|
||||
$stats['unused'],
|
||||
));
|
||||
}
|
||||
|
||||
$this->newLine();
|
||||
$this->info(sprintf(
|
||||
'Gesamt: referenziert %d, kopiert %d, Varianten %d, DB-Updates %d, bereits synchron %d, fehlend %d, ungenutzt %d%s',
|
||||
$totals['referenced'],
|
||||
$totals['copied'],
|
||||
$totals['variants_generated'],
|
||||
$totals['updated'],
|
||||
$totals['already_synced'],
|
||||
$totals['missing'],
|
||||
$totals['unused'],
|
||||
$dryRun ? ' (Dry-Run)' : '',
|
||||
));
|
||||
|
||||
return $totals['missing'] > 0 ? self::FAILURE : self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function selectedPortals(): array
|
||||
{
|
||||
$portal = (string) $this->option('portal');
|
||||
|
||||
return match ($portal) {
|
||||
'all' => [Portal::Presseecho->value, Portal::Businessportal24->value],
|
||||
Portal::Presseecho->value, Portal::Businessportal24->value => [$portal],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{referenced:int,copied:int,variants_generated:int,updated:int,already_synced:int,missing:int,unused:int}
|
||||
*/
|
||||
private function syncPortal(string $portal, bool $dryRun, bool $force, bool $skipVariants, int $limit): array
|
||||
{
|
||||
$sourceDirectory = "{$portal}/press_release";
|
||||
$allSourceFiles = collect(Storage::disk('public')->files($sourceDirectory))
|
||||
->mapWithKeys(fn (string $path): array => [basename($path) => $path]);
|
||||
|
||||
$referencedFilenames = [];
|
||||
$stats = [
|
||||
'referenced' => 0,
|
||||
'copied' => 0,
|
||||
'variants_generated' => 0,
|
||||
'updated' => 0,
|
||||
'already_synced' => 0,
|
||||
'missing' => 0,
|
||||
'unused' => 0,
|
||||
];
|
||||
|
||||
$query = PressReleaseImage::withoutGlobalScopes()
|
||||
->where('legacy_portal', $portal)
|
||||
->whereNotNull('path')
|
||||
->select(['id', 'press_release_id', 'legacy_portal', 'path', 'variants'])
|
||||
->orderBy('id');
|
||||
|
||||
$processed = 0;
|
||||
$reachLimit = false;
|
||||
|
||||
$query->chunkById(500, function ($images) use (
|
||||
$allSourceFiles, $dryRun, $force, $skipVariants, $portal, $limit,
|
||||
&$referencedFilenames, &$stats, &$processed, &$reachLimit,
|
||||
): bool {
|
||||
foreach ($images as $image) {
|
||||
if ($reachLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stats['referenced']++;
|
||||
$sourceFilename = basename((string) $image->path);
|
||||
$referencedFilenames[$sourceFilename] = true;
|
||||
|
||||
if (Str::startsWith((string) $image->path, 'press-releases/')) {
|
||||
$stats['already_synced']++;
|
||||
|
||||
if (! $skipVariants && (! is_array($image->variants) || $image->variants === [])) {
|
||||
if (! $dryRun) {
|
||||
$variants = $this->imageService->generateMissingPressReleaseVariants($image->path);
|
||||
|
||||
if ($variants !== []) {
|
||||
$image->forceFill(['variants' => $variants])->save();
|
||||
$stats['variants_generated']++;
|
||||
$stats['updated']++;
|
||||
}
|
||||
} else {
|
||||
$stats['variants_generated']++;
|
||||
}
|
||||
}
|
||||
|
||||
$processed++;
|
||||
|
||||
if ($limit > 0 && $processed >= $limit) {
|
||||
$reachLimit = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourcePath = $allSourceFiles->get($sourceFilename);
|
||||
|
||||
if (! $sourcePath) {
|
||||
$stats['missing']++;
|
||||
$this->warn("Fehlt: {$portal}/press_release/{$sourceFilename} (Image #{$image->id})");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$destinationPath = "press-releases/{$image->press_release_id}/images/{$sourceFilename}";
|
||||
|
||||
if (! $dryRun) {
|
||||
if ($force || ! Storage::disk('public')->exists($destinationPath)) {
|
||||
Storage::disk('public')->copy($sourcePath, $destinationPath);
|
||||
$stats['copied']++;
|
||||
}
|
||||
} else {
|
||||
$stats['copied']++;
|
||||
}
|
||||
|
||||
$variants = [];
|
||||
if (! $skipVariants && ! $dryRun) {
|
||||
$variants = $this->imageService->generateMissingPressReleaseVariants($destinationPath);
|
||||
|
||||
if ($variants !== []) {
|
||||
$stats['variants_generated']++;
|
||||
}
|
||||
} elseif (! $skipVariants && $dryRun) {
|
||||
$stats['variants_generated']++;
|
||||
}
|
||||
|
||||
if (! $dryRun) {
|
||||
$size = @getimagesize(Storage::disk('public')->path($destinationPath)) ?: [null, null];
|
||||
|
||||
$image->forceFill([
|
||||
'disk' => 'public',
|
||||
'path' => $destinationPath,
|
||||
'variants' => $variants !== [] ? $variants : $image->variants,
|
||||
'width' => is_int($size[0] ?? null) ? $size[0] : $image->width,
|
||||
'height' => is_int($size[1] ?? null) ? $size[1] : $image->height,
|
||||
])->save();
|
||||
}
|
||||
|
||||
$stats['updated']++;
|
||||
$processed++;
|
||||
|
||||
if ($limit > 0 && $processed >= $limit) {
|
||||
$reachLimit = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
$stats['unused'] = $allSourceFiles->keys()
|
||||
->reject(fn (string $filename): bool => isset($referencedFilenames[$filename]))
|
||||
->count();
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue