diff --git a/packages/ep_theme/Classes/Command/MigrateGridelementsCommand.php b/packages/ep_theme/Classes/Command/MigrateGridelementsCommand.php deleted file mode 100644 index 4781b46..0000000 --- a/packages/ep_theme/Classes/Command/MigrateGridelementsCommand.php +++ /dev/null @@ -1,218 +0,0 @@ - [container CType, first container colPos - 1, valid gridelements columns] - */ - private const LAYOUTS = [ - 'halves' => ['ep_container_halves', 200, [21, 22]], - 'thirds' => ['ep_container_thirds', 210, [31, 32, 33]], - 'quarters' => ['ep_container_columns_quarters', 220, [41, 42, 43, 44]], - 'halfAndTwoQuarters' => ['ep_container_half_and_two_quarters', 230, [51, 52, 53]], - 'twoQuartersAndHalf' => ['ep_container_two_quarters_and_half', 240, [61, 62, 63]], - ]; - - /** - * Content types whose template renders the header with settings.defaultHeaderType for layout 0 - */ - private const DEFAULT_HEADER_TYPES = ['text', 'textmedia', 'textpic']; - - private const RESET = [ - 'tx_gridelements_container' => 0, - 'tx_gridelements_columns' => 0, - 'tx_gridelements_children' => 0, - 'tx_gridelements_backend_layout' => '', - ]; - - public function __construct( - private readonly ConnectionPool $connectionPool, - ) { - parent::__construct(); - } - - protected function configure(): void - { - $this - ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Only show what would change') - ->addOption('report', null, InputOption::VALUE_REQUIRED, 'Write every row that is not migrated 1:1 to this CSV file'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $connection = $this->connectionPool->getConnectionForTable('tt_content'); - if (!$this->hasGridelementsColumns($connection)) { - $output->writeln('No tx_gridelements_* columns in tt_content, nothing to do.'); - return Command::SUCCESS; - } - - // Plain SQL on purpose: Connection::select() would apply the frontend restrictions (deleted, hidden, …) - $grids = []; - foreach ($connection->executeQuery('SELECT * FROM tt_content WHERE CType = ?', ['gridelements_pi1'])->iterateAssociative() as $row) { - $grids[(int)$row['uid']] = $row; - } - $children = $connection->executeQuery( - 'SELECT * FROM tt_content WHERE tx_gridelements_container > 0 AND CType <> ? ORDER BY uid', - ['gridelements_pi1'] - )->fetchAllAssociative(); - - if ((int)$connection->executeQuery('SELECT COUNT(*) FROM tt_content WHERE CType = ? AND sys_language_uid > 0', ['gridelements_pi1'])->fetchOne() > 0) { - $output->writeln('Translated grids found; translations are not handled by this command.'); - return Command::FAILURE; - } - - $updates = []; - $counts = []; - $report = []; - $count = static function (string $key) use (&$counts): void { - $counts[$key] = ($counts[$key] ?? 0) + 1; - }; - - foreach ($grids as $uid => $grid) { - $layout = (string)$grid['tx_gridelements_backend_layout']; - if (isset(self::LAYOUTS[$layout])) { - $updates[$uid] = ['CType' => self::LAYOUTS[$layout][0], 'pi_flexform' => ''] + self::RESET; - $count('grid ' . $layout . ((int)$grid['deleted'] ? ' (deleted)' : '')); - continue; - } - // A grid without layout renders nothing; keep it restorable as an empty container - $updates[$uid] = ['CType' => 'ep_container_halves', 'pi_flexform' => '', 'deleted' => 1] + self::RESET; - $count('grid without layout → deleted'); - if (!(int)$grid['deleted']) { - $report[] = [$grid, 'grid', 'grid without layout', 'deleted']; - } - } - - foreach ($children as $child) { - $uid = (int)$child['uid']; - $parent = $grids[(int)$child['tx_gridelements_container']] ?? null; - $column = (int)$child['tx_gridelements_columns']; - - if ((int)$child['colPos'] >= 0) { - // Rendered in its page column, not by the grid (gridelements only queries colPos -1) - $updates[$uid] = self::RESET; - $count('child outside the grid (colPos ' . $child['colPos'] . '), stays'); - if (!(int)$child['deleted']) { - $report[] = [$child, 'page column', 'colPos ' . $child['colPos'] . ' instead of -1', 'unchanged, grid fields cleared']; - } - continue; - } - if ($parent !== null && (int)$child['pid'] !== (int)$parent['pid']) { - // A container only renders children of its own page - $parent = null; - } - $config = self::LAYOUTS[(string)($parent['tx_gridelements_backend_layout'] ?? '')] ?? null; - if ($parent !== null && $config !== null && (int)$child['colPos'] === -1 && in_array($column, $config[2], true)) { - $updates[$uid] = [ - 'tx_container_parent' => (int)$parent['uid'], - 'colPos' => $config[1] + $column % 10, - ] + self::RESET; - $count('A: child migrated' . ((int)$child['deleted'] ? ' (deleted)' : '')); - // Inside a grid, TYPO3 10 did not apply settings.defaultHeaderType, so the header of these - // types stayed invisible with layout "default". Keep it invisible, and visible as such to editors. - if ((int)$child['header_layout'] === 0 && trim((string)$child['header']) !== '' && in_array($child['CType'], self::DEFAULT_HEADER_TYPES, true)) { - $updates[$uid]['header_layout'] = 100; - $count('A: header layout default → hidden'); - } - continue; - } - // B (column not in the layout) and C (parent is no grid): invisible in TYPO3 10, soft deleted - $group = $parent === null ? 'C' : 'B'; - $reason = $parent === null - ? 'parent ' . $child['tx_gridelements_container'] . ' is not a grid on the same page' - : 'column ' . $column . ' (colPos ' . $child['colPos'] . ') not in layout ' . $parent['tx_gridelements_backend_layout']; - $updates[$uid] = ['deleted' => 1] + self::RESET; - $count($group . ': child deleted' . ((int)$child['deleted'] ? ' (was deleted already)' : '')); - if (!(int)$child['deleted']) { - $report[] = [$child, $group, $reason, 'deleted']; - } - } - - // Other rows still carrying grid values (e.g. a former grid whose CType was changed by hand) - $leftovers = (int)$connection->executeQuery( - 'SELECT COUNT(*) FROM tt_content WHERE (tx_gridelements_children > 0 OR tx_gridelements_backend_layout NOT IN (\'\', \'0\')) AND CType <> ? AND tx_gridelements_container = 0', - ['gridelements_pi1'] - )->fetchOne(); - - ksort($counts); - foreach ($counts as $label => $number) { - $output->writeln(sprintf('%6d %s', $number, $label)); - } - if ($leftovers > 0) { - $output->writeln(sprintf('%6d other rows with grid values, cleared', $leftovers)); - } - if ($input->getOption('report')) { - if (!$this->writeReport((string)$input->getOption('report'), $report)) { - $output->writeln(sprintf('Cannot write the report to %s, nothing migrated.', $input->getOption('report'))); - return Command::FAILURE; - } - $output->writeln(sprintf('Report: %d rows in %s', count($report), $input->getOption('report'))); - } - if ($updates === [] && $leftovers === 0) { - $output->writeln('Nothing to migrate.'); - return Command::SUCCESS; - } - if ($input->getOption('dry-run')) { - $output->writeln('Dry run, nothing written.'); - return Command::SUCCESS; - } - - $connection->transactional(function (Connection $connection) use ($updates): void { - foreach ($updates as $uid => $values) { - $connection->update('tt_content', $values, ['uid' => $uid]); - } - $connection->executeStatement( - 'UPDATE tt_content SET tx_gridelements_children = 0, tx_gridelements_backend_layout = \'\' WHERE tx_gridelements_children > 0 OR tx_gridelements_backend_layout NOT IN (\'\', \'0\')' - ); - }); - - $output->writeln(sprintf('%d rows migrated. Next: referenceindex:update, container:integrity, cache:flush', count($updates))); - return Command::SUCCESS; - } - - private function hasGridelementsColumns(Connection $connection): bool - { - return array_key_exists('tx_gridelements_container', $connection->createSchemaManager()->listTableColumns('tt_content')); - } - - /** - * @param list, 1: string, 2: string, 3: string}> $rows - */ - private function writeReport(string $file, array $rows): bool - { - $handle = @fopen($file, 'wb'); - if ($handle === false) { - return false; - } - $titles = []; - foreach ($this->connectionPool->getConnectionForTable('pages')->executeQuery('SELECT uid, title FROM pages WHERE sys_language_uid = 0')->iterateAssociative() as $page) { - $titles[(int)$page['uid']] = $page['title']; - } - fputcsv($handle, ['uid', 'pid', 'page', 'CType', 'header', 'hidden', 'group', 'reason', 'action'], escape: ''); - foreach ($rows as [$row, $group, $reason, $action]) { - fputcsv($handle, [ - $row['uid'], $row['pid'], $titles[(int)$row['pid']] ?? '', $row['CType'], $row['header'], $row['hidden'], $group, $reason, $action, - ], escape: ''); - } - return fclose($handle); - } -} diff --git a/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php b/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php index 5b4d438..ab5a8c3 100644 --- a/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php +++ b/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php @@ -31,7 +31,7 @@ call_user_func(function () { ) ); - // Column layouts, migrated from gridelements (ep:migrate-gridelements). colPos = 200 + 10 × layout + column + // Column layouts, migrated from gridelements in 2026 (commit 4172ed9). colPos = 200 + 10 × layout + column $menus = 'menu_abstract,menu_categorized_content,menu_categorized_pages,menu_recently_updated,menu_related_pages,menu_section_pages,menu_sitemap,menu_sitemap_pages'; $columnContainers = [ 'ep_container_halves' => ['Spalten 50/50', 'Zwei gleich breite Spalten', 'halves', [[201], [202]]], diff --git a/packages/ep_theme/ext_tables.sql b/packages/ep_theme/ext_tables.sql index 98bb4f1..40379df 100644 --- a/packages/ep_theme/ext_tables.sql +++ b/packages/ep_theme/ext_tables.sql @@ -182,44 +182,3 @@ CREATE TABLE tx_eptheme_ttcontent_tx_eptheme_disrupter_mm KEY uid_local (uid_local), KEY uid_foreign (uid_foreign) ); - -CREATE TABLE tx_eptheme_domain_model_addresscheck -( - uid int(11) NOT NULL auto_increment, - pid int(11) DEFAULT '0' NOT NULL, - tstamp int(11) DEFAULT '0' NOT NULL, - crdate int(11) DEFAULT '0' NOT NULL, - cruser_id int(11) DEFAULT '0' NOT NULL, - deleted tinyint(3) DEFAULT '0', - hidden tinyint(4) DEFAULT '0' NOT NULL, - - name tinytext, - first_name tinytext, - last_name tinytext, - customer_id varchar(255) DEFAULT '' NOT NULL, - title varchar(255) DEFAULT '' NOT NULL, - email varchar(255) DEFAULT '' NOT NULL, - address tinytext, - city varchar(255) DEFAULT '' NOT NULL, - zip varchar(20) DEFAULT '' NOT NULL, - country varchar(128) DEFAULT '' NOT NULL, - - no_postal tinyint(4) DEFAULT '0' NOT NULL, - no_email tinyint(4) DEFAULT '0' NOT NULL, - address_current tinyint(4) DEFAULT '0' NOT NULL, - - t3ver_oid int(11) DEFAULT '0' NOT NULL, - t3ver_id int(11) DEFAULT '0' NOT NULL, - t3ver_wsid int(11) DEFAULT '0' NOT NULL, - t3ver_label varchar(30) DEFAULT '' NOT NULL, - t3ver_state tinyint(4) DEFAULT '0' NOT NULL, - t3ver_stage tinyint(4) DEFAULT '0' NOT NULL, - t3ver_count int(11) DEFAULT '0' NOT NULL, - t3ver_tstamp int(11) DEFAULT '0' NOT NULL, - t3ver_move_id int(11) DEFAULT '0' NOT NULL, - t3_origuid int(11) DEFAULT '0' NOT NULL, - - PRIMARY KEY (uid), - KEY parent (pid), - KEY pid (pid, email) -);