PressReleaseStatus::Draft, 'edited' => PressReleaseStatus::Draft, 'prepublished' => PressReleaseStatus::Review, 'published' => PressReleaseStatus::Published, 'rejected' => PressReleaseStatus::Rejected, ]; public function run(ImportContext $ctx): ImportResult { $result = new ImportResult; $conn = $ctx->connection; $legacyPortal = $ctx->legacyPortalValue(); $portal = $ctx->portalEnum; // Bilder und Kontakt-Pivots vorladen $images = DB::connection($conn) ->table('press_release_image') ->get() ->groupBy('press_release_id'); $prContacts = DB::connection($conn) ->table('press_release_contact') ->get() ->groupBy('press_release_id'); DB::connection($conn) ->table('press_release') ->orderBy('id') ->chunk(self::CHUNK_SIZE, function ($rows) use ($ctx, $result, $legacyPortal, $portal, $images, $prContacts): void { foreach ($rows as $row) { try { $this->importRow($row, $ctx, $result, $legacyPortal, $portal, $images, $prContacts); } catch (\Throwable $e) { $result->addError("PR legacy_id={$row->id}: {$e->getMessage()}"); } } }); return $result; } private function importRow( object $row, ImportContext $ctx, ImportResult $result, string $legacyPortal, Portal $portal, Collection $images, Collection $prContacts, ): void { $alreadyImported = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'press_release') ->where('legacy_id', $row->id) ->exists(); if ($alreadyImported && ! $ctx->force) { $result->incrementSkipped(); return; } if ($ctx->dryRun) { $result->incrementImported(); return; } // User aus Import-Map $userId = null; if ($row->user_id) { $userMap = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'sf_guard_user') ->where('legacy_id', $row->user_id) ->first(); $userId = $userMap?->target_id; } if (! $userId) { $result->incrementSkipped(); return; } // Company aus Import-Map $companyId = null; if ($row->company_id) { $companyMap = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'company') ->where('legacy_id', $row->company_id) ->first(); $companyId = $companyMap?->target_id; } // Kategorie aus Import-Map $categoryId = null; if ($row->category_id) { $catMap = LegacyImportMap::query() ->where('legacy_table', 'category') ->where('legacy_id', $row->category_id) ->first(); $categoryId = $catMap?->target_id; } // Fallback-Kategorie (erste verfügbare) if (! $categoryId) { $categoryId = LegacyImportMap::query() ->where('legacy_table', 'category') ->value('target_id'); } if (! $categoryId) { $result->incrementSkipped(); return; } $status = self::STATUS_MAP[$row->status] ?? PressReleaseStatus::Draft; $language = in_array($row->language, ['de', 'en']) ? $row->language : 'de'; // Beim Update (--force): bestehenden Slug behalten, um Kollisionen zu vermeiden. $existingPr = $alreadyImported ? PressRelease::withoutGlobalScopes() ->where('legacy_portal', $legacyPortal) ->where('legacy_id', $row->id) ->first(['id', 'slug']) : null; $slug = $existingPr?->slug ?? $this->uniqueSlug( $row->slug ?: Str::slug($row->title) ?: 'pressemitteilung', $portal->value, $language, $existingPr?->id, ); $publishedAt = ($status === PressReleaseStatus::Published) ? ($row->updated_at ?? $row->created_at) : null; $pr = PressRelease::withoutTimestamps(function () use ( $legacyPortal, $row, $portal, $userId, $companyId, $categoryId, $language, $slug, $status, $publishedAt, ): PressRelease { return PressRelease::withoutGlobalScopes()->updateOrCreate( ['legacy_portal' => $legacyPortal, 'legacy_id' => $row->id], [ 'uuid' => (string) Str::uuid(), 'portal' => $portal->value, 'user_id' => $userId, 'company_id' => $companyId, 'category_id' => $categoryId, 'language' => $language, 'title' => $row->title ?: 'Ohne Titel', 'slug' => $slug, 'text' => $row->text ?: '', 'backlink_url' => $row->backlink_url ?: null, 'keywords' => $row->keywords ?: null, 'status' => $status->value, 'hits' => max(0, (int) $row->hits), 'teaser_begin' => max(0, (int) ($row->teaser_begin ?? 0)), 'teaser_end' => max(0, (int) ($row->teaser_end ?? 0)), 'no_export' => (bool) ($row->no_export ?? false), 'published_at' => $publishedAt, 'created_at' => $row->created_at ?? now(), 'updated_at' => $row->updated_at ?? $row->created_at ?? now(), ] ); }); foreach ($images->get($row->id, []) as $img) { PressReleaseImage::withoutGlobalScopes()->updateOrCreate( ['legacy_portal' => $legacyPortal, 'legacy_id' => $img->id], [ 'press_release_id' => $pr->id, 'path' => $img->image, 'title' => $img->title ?: null, 'description' => $img->description ?: null, 'copyright' => $img->copyright ?: null, 'is_preview' => (bool) $img->is_preview_image, 'sort_order' => 0, ] ); } // Kontakt-Pivot importieren $contactIds = []; foreach ($prContacts->get($row->id, []) as $pivot) { $contactMap = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'contact') ->where('legacy_id', $pivot->contact_id) ->first(); if ($contactMap) { $contactIds[] = $contactMap->target_id; } } if ($contactIds !== []) { $pr->contacts()->syncWithoutDetaching($contactIds); } LegacyImportMap::query()->updateOrCreate( [ 'legacy_portal' => $legacyPortal, 'legacy_table' => 'press_release', 'legacy_id' => $row->id, ], [ 'target_table' => 'press_releases', 'target_id' => $pr->id, 'imported_at' => now(), ] ); if ($alreadyImported) { $result->incrementUpdated(); } else { $result->incrementImported(); } } private function uniqueSlug(string $base, string $portal, string $language, ?int $excludeId = null): string { $slug = $base; $i = 2; while (PressRelease::withoutGlobalScopes() ->where('portal', $portal) ->where('language', $language) ->where('slug', $slug) ->when($excludeId, fn ($q) => $q->where('id', '!=', $excludeId)) ->exists() ) { $slug = $base.'-'.$i++; } return $slug; } }