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'); $totals = [ 'referenced' => 0, 'copied' => 0, 'updated' => 0, 'already_synced' => 0, 'missing' => 0, 'unused' => 0, ]; foreach ($portals as $portal) { $stats = $this->syncPortal($portal, $dryRun, $force); foreach ($totals as $key => $value) { $totals[$key] = $value + $stats[$key]; } $this->line(sprintf( '%s: referenziert %d, kopiert %d, DB-Updates %d, bereits synchron %d, fehlend %d, ungenutzt %d', $portal, $stats['referenced'], $stats['copied'], $stats['updated'], $stats['already_synced'], $stats['missing'], $stats['unused'], )); } $this->newLine(); $this->info(sprintf( 'Gesamt: referenziert %d, kopiert %d, DB-Updates %d, bereits synchron %d, fehlend %d, ungenutzt %d%s', $totals['referenced'], $totals['copied'], $totals['updated'], $totals['already_synced'], $totals['missing'], $totals['unused'], $dryRun ? ' (Dry-Run)' : '', )); return $totals['missing'] > 0 ? self::FAILURE : self::SUCCESS; } /** * @return list */ 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,updated:int,already_synced:int,missing:int,unused:int} */ private function syncPortal(string $portal, bool $dryRun, bool $force): array { $sourceDirectory = "{$portal}/company"; $allSourceFiles = collect(Storage::disk('public')->files($sourceDirectory)) ->mapWithKeys(fn (string $path): array => [basename($path) => $path]); $referencedFilenames = []; $stats = [ 'referenced' => 0, 'copied' => 0, 'updated' => 0, 'already_synced' => 0, 'missing' => 0, 'unused' => 0, ]; Company::withoutGlobalScopes() ->where('legacy_portal', $portal) ->whereNotNull('logo_path') ->select(['id', 'legacy_portal', 'logo_path']) ->orderBy('id') ->chunkById(500, function ($companies) use ($allSourceFiles, $dryRun, $force, $portal, &$referencedFilenames, &$stats): void { foreach ($companies as $company) { $stats['referenced']++; $sourceFilename = basename((string) $company->logo_path); $referencedFilenames[$sourceFilename] = true; if (Str::startsWith((string) $company->logo_path, 'company-logos/')) { $stats['already_synced']++; continue; } $sourcePath = $allSourceFiles->get($sourceFilename); if (! $sourcePath) { $stats['missing']++; $this->warn("Fehlt: {$portal}/company/{$sourceFilename} (Company #{$company->id})"); continue; } $destinationPath = "company-logos/{$portal}/{$company->id}/{$sourceFilename}"; if (! $dryRun && ($force || ! Storage::disk('public')->exists($destinationPath))) { Storage::disk('public')->copy($sourcePath, $destinationPath); $stats['copied']++; } elseif ($dryRun || Storage::disk('public')->exists($destinationPath)) { $stats['copied'] += $dryRun ? 1 : 0; } if (! $dryRun) { $company->forceFill([ 'logo_path' => $destinationPath, ])->save(); } $stats['updated']++; } }); $stats['unused'] = $allSourceFiles->keys() ->reject(fn (string $filename): bool => isset($referencedFilenames[$filename])) ->count(); return $stats; } }