diff --git a/Classes/Listener/RecordSummaryForLocalization.php b/Classes/Listener/RecordSummaryForLocalization.php index c3d71a6e..d75236bf 100644 --- a/Classes/Listener/RecordSummaryForLocalization.php +++ b/Classes/Listener/RecordSummaryForLocalization.php @@ -14,6 +14,9 @@ use B13\Container\Service\RecordLocalizeSummaryModifier; use TYPO3\CMS\Backend\Controller\Event\AfterRecordSummaryForLocalizationEvent; +use TYPO3\CMS\Core\Database\Connection; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Information\Typo3Version; class RecordSummaryForLocalization { @@ -22,18 +25,115 @@ class RecordSummaryForLocalization */ protected $recordLocalizeSummaryModifier; - public function __construct(RecordLocalizeSummaryModifier $recordLocalizeSummaryModifier) - { + protected ConnectionPool $connectionPool; + + public function __construct( + RecordLocalizeSummaryModifier $recordLocalizeSummaryModifier, + ConnectionPool $connectionPool + ) { $this->recordLocalizeSummaryModifier = $recordLocalizeSummaryModifier; + $this->connectionPool = $connectionPool; } public function __invoke(AfterRecordSummaryForLocalizationEvent $event): void { $records = $event->getRecords(); - $columns = $event->getColumns(); - $records = $this->recordLocalizeSummaryModifier->filterRecords($records); - $columns = $this->recordLocalizeSummaryModifier->rebuildColumns($columns); - $event->setColumns($columns); + if ((new Typo3Version())->getMajorVersion() < 14) { + $columns = $event->getColumns(); + $records = $this->recordLocalizeSummaryModifier->filterRecords($records); + $columns = $this->recordLocalizeSummaryModifier->rebuildColumns($columns); + $event->setColumns($columns); + $event->setRecords($records); + return; + } + $localizeRecords = []; + foreach ($records as $colPos => $recordsPerColPos) { + foreach ($recordsPerColPos as $record) { + $localizeRecords[$record['uid']] = $record; + } + } + $fullRecords = $this->fetchAllRecords(array_keys($localizeRecords)); + $records = $this->moveContainerColPosIntoPageColPos($fullRecords, $localizeRecords); $event->setRecords($records); } + + protected function moveContainerColPosIntoPageColPos(array $records, array $localizeRecords): array + { + $recordsPerColPos = []; + foreach ($records as $record) { + $colPos = $this->resolveRecordColPos($record, $localizeRecords); + if (!isset($recordsPerColPos[$colPos])) { + $recordsPerColPos[$colPos] = []; + } + if (!isset($localizeRecords[$record['uid']])) { + throw new RecordSummaryForLocalizationException('localizeRecord not set ' . $record['uid'], 1769247959); + } + $recordsPerColPos[$colPos][] = $localizeRecords[$record['uid']]; + } + return $recordsPerColPos; + } + + protected function resolveRecordColPos(array $record, $localizeRecords): int + { + if (($record['tx_container_parent'] ?? 0) === 0) { + return $record['colPos']; + } + $loopCnt = 0; + $maxDepth = 20; + $containerUid = $record['tx_container_parent']; + while (true) { + if (in_array($containerUid, array_keys($localizeRecords))) { + return $record['colPos']; + } + if ($loopCnt > $maxDepth) { + throw new RecordSummaryForLocalizationException('maxDepth has reached ' . $maxDepth, 1769247958); + } + $containerRecord = $this->fetchOneRecord($containerUid); + if ($containerRecord === null) { + throw new RecordSummaryForLocalizationException('cannot fetch record for uid ' . $containerUid, 1769247957); + } + if (($containerRecord['tx_container_parent'] ?? 0) === 0) { + return $containerRecord['colPos']; + } + $containerUid = $containerRecord['tx_container_parent']; + $loopCnt++; + } + } + + protected function fetchOneRecord(int $uid): ?array + { + $queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content'); + $row = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 'uid', + $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT) + ) + ) + ->executeQuery() + ->fetchAssociative(); + return $row ?: null; + } + + protected function fetchAllRecords(array $uids): array + { + $queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content'); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->in( + 'uid', + $queryBuilder->createNamedParameter($uids, Connection::PARAM_INT_ARRAY) + ) + ) + ->orderBy('sorting') + ->executeQuery() + ->fetchAllAssociative(); + $rowsPerUid = []; + foreach ($rows as $row) { + $rowsPerUid[$row['uid']] = $row; + } + return $rowsPerUid; + } } diff --git a/Classes/Listener/RecordSummaryForLocalizationException.php b/Classes/Listener/RecordSummaryForLocalizationException.php new file mode 100644 index 00000000..f0bb1f94 --- /dev/null +++ b/Classes/Listener/RecordSummaryForLocalizationException.php @@ -0,0 +1,19 @@ +click('a.t3js-localize'); } else { $I->waitForText('Translate'); - $I->executeJS("document.querySelector('typo3-backend-localization-button').click()"); - // AfterRecordSummaryForLocalizationEvent - $scenario->skip('need more work, AfterRecordSummaryForLocalizationEvent needs refactoring'); + $I->executeJS("document.querySelector('#PageLayoutController typo3-backend-localization-button').click()"); } $I->switchToIFrame(); @@ -405,7 +403,11 @@ public function canTranslateChildWithTranslationModule(BackendTester $I, PageTre $I->waitForElement('.t3js-localization-option'); $I->waitForElement('div[data-bs-slide="localize-summary"]'); } - $I->waitForText('(212) headerOfChild'); + if ($I->getTypo3MajorVersion() < 14) { + $I->waitForText('(212) headerOfChild'); + } else { + $I->waitForText('headerOfChild'); + } } /** diff --git a/Tests/Functional/Listener/Fixtures/localize_container.csv b/Tests/Functional/Listener/Fixtures/localize_container.csv new file mode 100644 index 00000000..7c2aad3b --- /dev/null +++ b/Tests/Functional/Listener/Fixtures/localize_container.csv @@ -0,0 +1,8 @@ +"tt_content" +,"uid","pid","CType","header","sorting","sys_language_uid","colPos","tx_container_parent","l18n_parent" +,"4","1","header","ce 2","288","0","200","5","0" +,"5","1","b13-2cols-with-header-container","container","256","0","0","0","0" +"pages" +,"uid","pid","sys_language_uid","l10n_parent" +,"1","0","0","0" +,"2","0","1","1" diff --git a/Tests/Functional/Listener/Fixtures/localize_container_child.csv b/Tests/Functional/Listener/Fixtures/localize_container_child.csv new file mode 100644 index 00000000..eef94f2d --- /dev/null +++ b/Tests/Functional/Listener/Fixtures/localize_container_child.csv @@ -0,0 +1,11 @@ +"tt_content" +,"uid","pid","CType","header","sorting","sys_language_uid","colPos","tx_container_parent","l18n_parent" +,"4","1","header","ce 2","288","0","200","5","0" +,"5","1","b13-2cols-with-header-container","container","256","0","0","0","0" +,"38","1","b13-2cols-with-header-container","translated container","272","1","0","0","5" +,"40","1","header","last element","300","0","0","0","0" +,"41","1","header","first element","128","0","0","0","0" +"pages" +,"uid","pid","sys_language_uid","l10n_parent" +,"1","0","0","0" +,"2","0","1","1" diff --git a/Tests/Functional/Listener/RecordSummaryForLocalization.php b/Tests/Functional/Listener/RecordSummaryForLocalization.php new file mode 100644 index 00000000..e4c6730f --- /dev/null +++ b/Tests/Functional/Listener/RecordSummaryForLocalization.php @@ -0,0 +1,94 @@ +getMajorVersion() < 14) { + self::markTestSkipped('tested by RecordLocalizeSummaryModifierTest Unit Test'); + } + $records = [ + 0 => [ + 0 => ['uid' => 41, 'title' => 'first element'], + 1 => ['uid' => 40, 'title' => 'last element'], + ], + 200 => [ + 0 => ['uid' => 4, 'title' => 'ce 2'], + ], + ]; + $columns = [0 => 'Normal']; + $event = new AfterRecordSummaryForLocalizationEvent($records, $columns); + $this->importCSVDataSet(__DIR__ . '/Fixtures/localize_container_child.csv'); + $listener = $this->getContainer()->get(\B13\Container\Listener\RecordSummaryForLocalization::class); + $listener($event); + $records = $event->getRecords(); + $expected = [ + 0 => [ + 0 => ['uid' => 41, 'title' => 'first element'], + 1 => ['uid' => 4, 'title' => 'ce 2'], + 2 => ['uid' => 40, 'title' => 'last element'], + ], + ]; + self::assertSame($expected, $records); + } + + /** + * @test + */ + public function childrenIsNotMovedIntoBackendLayoutColPosIfContainerShouldBeTranslated(): void + { + if ((new Typo3Version())->getMajorVersion() < 14) { + self::markTestSkipped('tested by RecordLocalizeSummaryModifierTest Unit Test'); + } + $records = [ + 0 => [ + 0 => ['uid' => 5, 'title' => 'container'], + ], + 200 => [ + 0 => ['uid' => 4, 'title' => 'ce 2'], + ], + ]; + $columns = [0 => 'Normal']; + $event = new AfterRecordSummaryForLocalizationEvent($records, $columns); + $this->importCSVDataSet(__DIR__ . '/Fixtures/localize_container.csv'); + $listener = $this->getContainer()->get(\B13\Container\Listener\RecordSummaryForLocalization::class); + $listener($event); + $records = $event->getRecords(); + $expected = [ + 0 => [ + 0 => ['uid' => 5, 'title' => 'container'], + ], + 200 => [ + 0 => ['uid' => 4, 'title' => 'ce 2'], + ], + ]; + self::assertSame($expected, $records); + } +} diff --git a/Tests/Unit/Service/RecordLocalizeSummaryModifierTest.php b/Tests/Unit/Service/RecordLocalizeSummaryModifierTest.php index d1224a22..3e3a6290 100644 --- a/Tests/Unit/Service/RecordLocalizeSummaryModifierTest.php +++ b/Tests/Unit/Service/RecordLocalizeSummaryModifierTest.php @@ -14,6 +14,7 @@ use B13\Container\Service\RecordLocalizeSummaryModifier; use B13\Container\Tca\Registry; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; class RecordLocalizeSummaryModifierTest extends UnitTestCase @@ -25,6 +26,9 @@ class RecordLocalizeSummaryModifierTest extends UnitTestCase */ public function filterRecordsRemovesContainerChildrenIfParentContainerIsTranslatedAsWell(): void { + if ((new Typo3Version())->getMajorVersion() >= 14) { + self::markTestSkipped('not used in v14'); + } $recordLocalizeSummeryModifier = $this->getAccessibleMock( RecordLocalizeSummaryModifier::class, ['getContainerUids', 'getContainerChildren'], @@ -48,6 +52,9 @@ public function filterRecordsRemovesContainerChildrenIfParentContainerIsTranslat */ public function filterRecordsKeepsContainerChildrenIfParentContainerIsNotTranslated(): void { + if ((new Typo3Version())->getMajorVersion() >= 14) { + self::markTestSkipped('not used in v14'); + } $recordLocalizeSummeryModifier = $this->getAccessibleMock( RecordLocalizeSummaryModifier::class, ['getContainerUids', 'getContainerChildren'], @@ -71,6 +78,9 @@ public function filterRecordsKeepsContainerChildrenIfParentContainerIsNotTransla */ public function rebuildColumnsReturnsColumnListWithConsecutiveArrayKeysAlsoWhenRegistryReturnsRepeatingColumns(): void { + if ((new Typo3Version())->getMajorVersion() >= 14) { + self::markTestSkipped('not used in v14'); + } $tcaRegistry = $this->getMockBuilder(Registry::class) ->disableOriginalConstructor() ->onlyMethods(['getAllAvailableColumns'])