diff --git a/migrations/why_band_unwrap_20261111.php b/migrations/why_band_unwrap_20261111.php new file mode 100644 index 0000000..7ca43ec --- /dev/null +++ b/migrations/why_band_unwrap_20261111.php @@ -0,0 +1,161 @@ + Auto-Purge greift NICHT: + * danach cache:flush + vitec:ssr-purge/-warm mit den Pfaden. + * + * php migrations/why_band_unwrap_20261111.php # INSPECT (default) + * php migrations/why_band_unwrap_20261111.php --apply # schreibt + */ + +declare(strict_types=1); + +$apply = in_array('--apply', $argv, true); + +$settings = require __DIR__ . '/../config/system/settings.php'; +$db = $settings['DB']['Connections']['Default']; +$pdo = new PDO( + sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4', $db['host'] ?? 'localhost', $db['port'] ?? 3306, $db['dbname'] ?? ''), + $db['user'] ?? '', $db['password'] ?? '', + [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] +); + +echo $apply ? "APPLY\n\n" : "INSPECT - nichts wird geschrieben (--apply zum Schreiben)\n\n"; + +$slugs = [ + '/products/graphics-and-multi-display', + '/products/infrastructure-and-accessories', + '/products/video-capture', +]; + +$norm = static fn(string $s): string => (string)preg_replace('/[^a-z0-9]+/', '', strtolower($s)); + +$done = 0; +foreach ($slugs as $slug) { + $st = $pdo->prepare('SELECT uid, title FROM pages WHERE deleted = 0 AND slug = ? AND sys_language_uid = 0'); + $st->execute([$slug]); + $page = $st->fetch(); + if (!$page) { + echo "$slug: Seite NICHT gefunden - uebersprungen\n\n"; + continue; + } + $pid = (int)$page['uid']; + + $st = $pdo->prepare( + 'SELECT uid, CType, header, sorting, vitec_layout_variant FROM tt_content + WHERE pid = ? AND deleted = 0 AND colPos = 0 AND sys_language_uid = 0 + AND (tx_container_parent IS NULL OR tx_container_parent = 0) + ORDER BY sorting, uid' + ); + $st->execute([$pid]); + $top = $st->fetchAll(); + + echo "== $slug (pid $pid) \"{$page['title']}\" - " . count($top) . " Top-Level-Elemente in colPos 0\n"; + + // bereits umgebaut? (Band = Intro + direkt folgende Karten top-level) + $whyIdx = null; + foreach ($top as $i => $el) { + if ($el['CType'] === 'vitec_introparagraph' && str_starts_with($norm((string)$el['header']), 'whyvitec')) { + $whyIdx = $i; + break; + } + } + if ($whyIdx === null) { + echo " kein Why-VITEC-Intro gefunden - uebersprungen\n\n"; + continue; + } + $intro = $top[$whyIdx]; + if (isset($top[$whyIdx + 1]) && $top[$whyIdx + 1]['CType'] === 'vitec_card') { + echo " Band liegt bereits top-level hinter Intro #{$intro['uid']} - nichts zu tun\n\n"; + continue; + } + + // direkt folgende Container einsammeln, solange sie nur Karten enthalten + $containers = []; + $cards = []; + for ($i = $whyIdx + 1; $i < count($top); $i++) { + $el = $top[$i]; + if (!str_starts_with((string)$el['CType'], 'vitec_cols')) { + break; + } + $kids = $pdo->query( + 'SELECT uid, CType, header, colPos, sorting, vitec_layout_variant FROM tt_content + WHERE deleted = 0 AND tx_container_parent = ' . (int)$el['uid'] . ' ORDER BY colPos, sorting, uid' + )->fetchAll(); + $onlyCards = $kids !== [] && count(array_filter($kids, static fn(array $k): bool => $k['CType'] !== 'vitec_card')) === 0; + if (!$onlyCards) { + break; + } + $containers[] = $el; + foreach ($kids as $k) { + $cards[] = $k; + } + } + if ($cards === []) { + echo " Intro #{$intro['uid']} \"{$intro['header']}\" ohne folgende Karten-Container - uebersprungen\n\n"; + continue; + } + + printf(" Intro #%d \"%s\"\n", $intro['uid'], $intro['header']); + printf(" %d Container (#%s) mit %d Karte(n):\n", count($containers), implode(', #', array_column($containers, 'uid')), count($cards)); + foreach ($cards as $c) { + printf(" #%-6d %-14s \"%s\"\n", $c['uid'], (string)$c['vitec_layout_variant'], (string)$c['header']); + } + + // neue Reihenfolge: bis Intro, dann Karten, dann Rest ohne die Container + $containerUids = array_map('intval', array_column($containers, 'uid')); + $newOrder = []; + foreach ($top as $i => $el) { + if (in_array((int)$el['uid'], $containerUids, true)) { + continue; + } + $newOrder[] = ['uid' => (int)$el['uid'], 'label' => $el['CType'] . ' ' . $el['header']]; + if ($i === $whyIdx) { + foreach ($cards as $c) { + $newOrder[] = ['uid' => (int)$c['uid'], 'label' => 'vitec_card (icon_card) ' . $c['header']]; + } + } + } + echo " Neue Reihenfolge colPos 0:\n"; + $sorting = 0; + foreach ($newOrder as $el) { + $sorting += 256; + printf(" %5d #%-6d %s\n", $sorting, $el['uid'], $el['label']); + } + + if ($apply) { + $pdo->beginTransaction(); + $upCard = $pdo->prepare("UPDATE tt_content SET colPos = 0, tx_container_parent = 0, vitec_layout_variant = 'icon_card', tstamp = UNIX_TIMESTAMP() WHERE uid = ?"); + foreach ($cards as $c) { + $upCard->execute([(int)$c['uid']]); + } + $pdo->exec('UPDATE tt_content SET deleted = 1, tstamp = UNIX_TIMESTAMP() WHERE uid IN (' . implode(',', $containerUids) . ')'); + $upSort = $pdo->prepare('UPDATE tt_content SET sorting = ?, tstamp = UNIX_TIMESTAMP() WHERE uid = ?'); + $sorting = 0; + foreach ($newOrder as $el) { + $sorting += 256; + $upSort->execute([$sorting, $el['uid']]); + } + $pdo->commit(); + echo " GESCHRIEBEN\n"; + } + $done++; + echo "\n"; +} + +echo ($apply ? 'FERTIG' : 'WUERDE') . ": $done Seite(n) umgebaut.\n"; +if ($apply && $done > 0) { + echo "Danach: vendor/bin/typo3 cache:flush && vendor/bin/typo3 vitec:ssr-purge " . implode(' ', $slugs) . " && vendor/bin/typo3 vitec:ssr-warm " . implode(' ', $slugs) . "\n"; +}