addOption('dry-run', null, InputOption::VALUE_NONE, 'Report only - nothing written'); } protected function execute(InputInterface $input, OutputInterface $output): int { Bootstrap::initializeBackendAuthentication(); $dryRun = (bool)$input->getOption('dry-run'); $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::TABLE); $groups = array_keys(AlignSolutionsCommand::TARGET); // Existing records: titles for idempotency, slugs for collision checks. $existingByTitle = []; $usedSlugs = []; foreach ($connection->fetchAllAssociative( 'SELECT uid, title, slug, is_group FROM ' . self::TABLE . ' WHERE deleted = 0' ) as $row) { $existingByTitle[$this->normalize((string)$row['title'])] = $row; $usedSlugs[(string)$row['slug']] = true; } $pids = $connection->fetchFirstColumn('SELECT pid FROM ' . self::TABLE . ' WHERE deleted = 0'); $pidCounts = array_count_values(array_map('intval', $pids)); arsort($pidCounts); $storagePid = (int)(array_key_first($pidCounts) ?? 0); if ($storagePid <= 0) { $output->writeln('No storage pid detectable (no solution records?)'); return Command::FAILURE; } // Group categories below the root category "Solution". $rootCat = (int)($connection->fetchOne( "SELECT uid FROM sys_category WHERE deleted = 0 AND parent = 0 AND title = 'Solution'" ) ?: 0); $catByTitle = []; if ($rootCat > 0) { foreach ($connection->fetchAllAssociative( 'SELECT uid, title FROM sys_category WHERE deleted = 0 AND parent = ?', [$rootCat] ) as $row) { $catByTitle[$this->normalize((string)$row['title'])] = (int)$row['uid']; } } // Candidate pages: standard pages, hidden allowed (map-solution-pages rule). $pagesByTitle = []; foreach ($connection->fetchAllAssociative( 'SELECT uid, title, slug FROM pages WHERE deleted = 0 AND doktype = 1' ) as $row) { $pagesByTitle[$this->normalize((string)$row['title'])][] = $row; } $datamap = []; $newIndex = 0; $created = 0; foreach ($groups as $group) { $key = $this->normalize($group); $existing = $existingByTitle[$key] ?? null; if ($existing !== null) { $state = ((int)$existing['is_group'] === 1) ? 'ok (is_group=1)' : 'KONFLIKT: Record gleichen Titels ohne is_group'; $output->writeln(sprintf(' %-45s existiert, uid %d - %s', $group, (int)$existing['uid'], $state)); continue; } $pageUid = 0; $candidates = $pagesByTitle[$key] ?? []; if (count($candidates) > 1) { // `-N` duplicate slugs lose the disambiguation. $candidates = array_values(array_filter( $candidates, static fn(array $p): bool => !preg_match('/-\d+$/', (string)$p['slug']) )) ?: $candidates; } if (count($candidates) === 1) { $pageUid = (int)$candidates[0]['uid']; } elseif (count($candidates) > 1) { $output->writeln(sprintf(' %s: Seite mehrdeutig (%d Kandidaten) - detail_page bleibt leer', $group, count($candidates))); } else { $output->writeln(sprintf(' %s: keine Gruppen-Seite gefunden - detail_page bleibt leer', $group)); } $slug = $this->slugFor($group, $usedSlugs); $fields = [ 'pid' => $storagePid, 'title' => $group, 'slug' => $slug, 'is_group' => 1, 'detail_page' => $pageUid, ]; $catUid = $catByTitle[$key] ?? 0; if ($catUid > 0) { $fields['categories'] = (string)$catUid; } else { $output->writeln(sprintf(' %s: keine Gruppen-Kategorie gefunden', $group)); } $output->writeln(sprintf( ' %-45s %s slug=%s page=%s cat=%s', $group, $dryRun ? 'wuerde angelegt' : 'anlegen', $slug, $pageUid ?: '-', $catUid ?: '-' )); $datamap[self::TABLE]['NEWGROUP' . (++$newIndex)] = $fields; $created++; } if ($dryRun) { $output->writeln(sprintf('DRY-RUN: %d Gruppen-Records wuerden angelegt.', $created)); return Command::SUCCESS; } if ($datamap !== []) { $dataHandler = GeneralUtility::makeInstance(DataHandler::class); $dataHandler->start($datamap, []); $dataHandler->process_datamap(); foreach ($dataHandler->errorLog as $error) { $output->writeln("$error"); } } $output->writeln(sprintf('%d Gruppen-Records angelegt.', $created)); return Command::SUCCESS; } private function normalize(string $title): string { $title = str_replace('&', 'and', mb_strtolower($title)); $title = (string)preg_replace('/[^a-z0-9]+/', ' ', $title); return trim((string)preg_replace('/\s+/', ' ', $title)); } /** @param array $usedSlugs */ private function slugFor(string $title, array &$usedSlugs): string { $slug = trim((string)preg_replace('/[^a-z0-9]+/', '-', str_replace('&', 'and', mb_strtolower($title))), '-'); $candidate = $slug; $i = 1; while (isset($usedSlugs[$candidate])) { $candidate = $slug . '-group' . ($i > 1 ? '-' . $i : ''); $i++; } $usedSlugs[$candidate] = true; return $candidate; } }