withoutGlobalScope(PortalScope::class) ->whereNull('gone_at') // Grobfilter in SQL (portabel, SQLite kennt kein REGEXP), die // eigentliche Erkennung macht der Normalizer in PHP. ->where(fn ($q) => $q->where('name', 'like', '%http://%') ->orWhere('name', 'like', '%https://%') ->orWhere('name', 'like', '%www.%') ->orWhere('name', 'like', '%/%')) ->orderBy('id'); // Ohne --all nur, was jemand sehen kann: aktive Firmen mit // veröffentlichter Meldung. Der Rest ist Datenmüll ohne Newsroom-Seite. if (! $this->option('all')) { $query->where('is_active', true) ->whereHas('pressReleases', fn ($q) => $q->withoutGlobalScope(PortalScope::class)->where('status', 'published')); } $rows = []; $changes = []; foreach ($query->cursor() as $company) { if (! CompanyNameNormalizer::containsUrl((string) $company->name)) { continue; } $normalized = CompanyNameNormalizer::normalize((string) $company->name, $company->website); if ($normalized['removed'] === [] || $normalized['name'] === $company->name) { continue; } $rows[] = [$company->id, $company->name, $normalized['name'], $normalized['website'] ?? '—']; $changes[] = [$company, $normalized]; } if ($rows === []) { $this->info('Keine Firmennamen mit Link gefunden.'); return self::SUCCESS; } $this->table(['ID', 'Vorher', 'Nachher', 'Website'], $rows); if ($this->option('dry-run')) { $this->info(sprintf('[Dry-Run] %d Firmennamen würden bereinigt.', count($rows))); return self::SUCCESS; } foreach ($changes as [$company, $normalized]) { $before = $company->name; $company->forceFill([ 'name' => $normalized['name'], 'website' => $normalized['website'], ])->save(); $activityLog->record( ActivityType::Correction, sprintf('Firma #%d: Link aus dem Namen entfernt („%s“ → „%s“)', $company->getKey(), $before, $company->name), null, $company, ['removed' => $normalized['removed']], 'system', ); } WebCaches::forgetPublicPages(); $this->info(sprintf('%d Firmennamen bereinigt.', count($changes))); return self::SUCCESS; } }