CompanyType::Agency, 'company' => CompanyType::Company, ]; public function run(ImportContext $ctx): ImportResult { $result = new ImportResult; $conn = $ctx->connection; $legacyPortal = $ctx->legacyPortalValue(); $portal = $ctx->portalEnum; // Verantwortliche User voraufladen (responsible_company_user) $responsibles = DB::connection($conn) ->table('responsible_company_user') ->get() ->groupBy('company_id') ->map(fn ($rows) => $rows->pluck('user_id')->all()); // Einfache company_user Mitglieder $members = DB::connection($conn) ->table('company_user') ->get() ->groupBy('company_id') ->map(fn ($rows) => $rows->pluck('user_id')->all()); DB::connection($conn) ->table('company') ->orderBy('id') ->chunk(self::CHUNK_SIZE, function ($rows) use ($ctx, $result, $legacyPortal, $portal, $responsibles, $members): void { foreach ($rows as $row) { try { $this->importRow($row, $ctx, $result, $legacyPortal, $portal, $responsibles, $members); } catch (\Throwable $e) { $result->addError("Company legacy_id={$row->id}: {$e->getMessage()}"); } } }); return $result; } private function importRow( object $row, ImportContext $ctx, ImportResult $result, string $legacyPortal, Portal $portal, Collection $responsibles, Collection $members, ): void { $alreadyImported = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'company') ->where('legacy_id', $row->id) ->exists(); if ($alreadyImported && ! $ctx->force) { $result->incrementSkipped(); return; } if ($ctx->dryRun) { $result->incrementImported(); return; } // Owner-User aus Import-Map auflösen $ownerUserId = null; if ($row->user_id) { $map = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'sf_guard_user') ->where('legacy_id', $row->user_id) ->first(); $ownerUserId = $map?->target_id; } $type = self::CTYPE_MAP[$row->ctype] ?? CompanyType::Company; // Eindeutigen Slug sicherstellen $slug = $this->uniqueSlug($row->slug ?: Str::slug($row->name) ?: 'firma', $portal->value); $company = Company::withoutTimestamps(function () use ($legacyPortal, $row, $portal, $ownerUserId, $type, $slug): Company { return Company::withoutGlobalScopes()->updateOrCreate( ['legacy_portal' => $legacyPortal, 'legacy_id' => $row->id], [ 'portal' => $portal->value, 'owner_user_id' => $ownerUserId, 'type' => $type->value, 'name' => $row->name ?: 'Unbekannte Firma', 'slug' => $slug, 'address' => $row->address ?: null, 'phone' => $this->cleanText($row->phone, 255), 'fax' => $this->cleanText($row->fax, 255), 'email' => $this->cleanText($row->email, 190), 'website' => $this->cleanText($row->website, 190), 'logo_path' => $row->logo ?: null, 'is_active' => (bool) $row->is_active, 'disable_footer_code' => (bool) ($row->disable_footer_code ?? false), 'created_at' => $row->created_at ?? now(), 'updated_at' => $row->updated_at ?? $row->created_at ?? now(), ] ); }); // Pivot-Zuordnungen (member + responsible) $pivotPayload = []; foreach ($members->get($row->id, []) as $legacyUserId) { $userMap = LegacyImportMap::query() ->where('legacy_portal', $legacyPortal) ->where('legacy_table', 'sf_guard_user') ->where('legacy_id', $legacyUserId) ->first(); if ($userMap) { $role = in_array($legacyUserId, $responsibles->get($row->id, [])) ? 'responsible' : 'member'; $pivotPayload[$userMap->target_id] = ['role' => $role]; } } if ($pivotPayload !== []) { $company->users()->syncWithoutDetaching($pivotPayload); } LegacyImportMap::query()->updateOrCreate( [ 'legacy_portal' => $legacyPortal, 'legacy_table' => 'company', 'legacy_id' => $row->id, ], [ 'target_table' => 'companies', 'target_id' => $company->id, 'imported_at' => now(), ] ); if ($alreadyImported) { $result->incrementUpdated(); } else { $result->incrementImported(); } } private function uniqueSlug(string $base, string $portal): string { $slug = $base; $i = 2; while (Company::withoutGlobalScopes() ->where('portal', $portal) ->where('slug', $slug) ->exists() ) { $slug = $base.'-'.$i++; } return $slug; } /** Bereinigt HTML-Entities und kürzt auf maximale Feldlänge. */ private function cleanText(?string $value, int $maxLength): ?string { if (blank($value)) { return null; } // HTML-Entities dekodieren (z.B.   → Thin Space → entfernen) $clean = html_entity_decode((string) $value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); // Steuerzeichen und unsichtbare Unicode-Zeichen entfernen $clean = preg_replace('/[\x00-\x1F\x7F\xC2\xA0]/u', ' ', $clean) ?? $clean; $clean = trim((string) $clean); if (blank($clean)) { return null; } return mb_substr($clean, 0, $maxLength); } }