diff --git a/Classes/Command/SortingInPageCommand.php b/Classes/Command/SortingInPageCommand.php index acc736c8..f3a960ea 100644 --- a/Classes/Command/SortingInPageCommand.php +++ b/Classes/Command/SortingInPageCommand.php @@ -32,6 +32,7 @@ class SortingInPageCommand extends Command protected function configure() { $this->addArgument('pid', InputArgument::OPTIONAL, 'limit to this pid', 0); + $this->addArgument('languageId', InputArgument::OPTIONAL, 'limit to this languageId', 0); $this->addOption('apply', null, InputOption::VALUE_NONE, 'apply migration'); $this->addOption( 'enable-logging', @@ -51,13 +52,17 @@ public function execute(InputInterface $input, OutputInterface $output): int { $dryrun = $input->getOption('apply') !== true; $pid = (int)$input->getArgument('pid'); + if ($input->getArgument('languageId') !== 'all') { + $languageId = (int)$input->getArgument('languageId'); + } Bootstrap::initializeBackendAuthentication(); $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromUserPreferences($GLOBALS['BE_USER']); $errors = $this->sorting->run( $dryrun, $input->getOption('enable-logging'), - $pid + $pid, + $languageId, ); foreach ($errors as $error) { $output->writeln($error); diff --git a/Classes/Domain/Service/ContainerService.php b/Classes/Domain/Service/ContainerService.php index 58687908..1256cb34 100644 --- a/Classes/Domain/Service/ContainerService.php +++ b/Classes/Domain/Service/ContainerService.php @@ -53,18 +53,26 @@ public function getNewContentElementAtTopTargetInColumn(Container $container, in return $target; } - public function getAfterContainerElementTarget(Container $container): int + public function getAfterContainerRecord(Container $container): array { - $target = -$container->getUid(); $childRecords = $container->getChildRecords(); if (empty($childRecords)) { - return $target; + return $container->getContainerRecord(); } + $lastChild = array_pop($childRecords); if (!$this->tcaRegistry->isContainerElement($lastChild['CType'])) { - return -(int)$lastChild['uid']; + return $lastChild; } + $container = $this->containerFactory->buildContainer((int)$lastChild['uid']); - return $this->getAfterContainerElementTarget($container); + return $this->getAfterContainerRecord($container); + } + + public function getAfterContainerElementTarget(Container $container): int + { + $target = $this->getAfterContainerRecord($container); + + return -$target['uid']; } } diff --git a/Classes/Integrity/Database.php b/Classes/Integrity/Database.php index 22a905ca..99f19de5 100644 --- a/Classes/Integrity/Database.php +++ b/Classes/Integrity/Database.php @@ -106,7 +106,7 @@ public function getChildrenByContainerAndColPos(int $containerId, int $colPos, i return $rows; } - public function getNonContainerChildrenPerColPos(array $containerUsedColPosArray, ?int $pid = null): array + public function getNonContainerChildrenPerColPos(array $containerUsedColPosArray, ?int $pid = null, ?int $languageId = null): array { $queryBuilder = $this->getQueryBuilder(); $stm = $queryBuilder @@ -116,12 +116,18 @@ public function getNonContainerChildrenPerColPos(array $containerUsedColPosArray $queryBuilder->expr()->notIn( 'colPos', $queryBuilder->createNamedParameter($containerUsedColPosArray, Connection::PARAM_INT_ARRAY) - ), + ) + ); + + if (!is_null($languageId)) { + $stm->andWhere( $queryBuilder->expr()->eq( 'sys_language_uid', - $queryBuilder->createNamedParameter(0, Connection::PARAM_INT) + $queryBuilder->createNamedParameter($languageId, Connection::PARAM_INT) ) ); + } + if (!empty($pid)) { $stm->andWhere( $queryBuilder->expr()->eq( @@ -136,7 +142,7 @@ public function getNonContainerChildrenPerColPos(array $containerUsedColPosArray $results = $stm->executeQuery()->fetchAllAssociative(); $rows = []; foreach ($results as $result) { - $key = $result['pid'] . '-' . $result['colPos']; + $key = $result['pid'] . '-' . $result['sys_language_uid'] . '-' . $result['colPos']; if (!isset($rows[$key])) { $rows[$key] = []; } diff --git a/Classes/Integrity/SortingInPage.php b/Classes/Integrity/SortingInPage.php index 39f48868..22d3f048 100644 --- a/Classes/Integrity/SortingInPage.php +++ b/Classes/Integrity/SortingInPage.php @@ -52,7 +52,7 @@ public function __construct(Database $database, Registry $tcaRegistry, Container $this->containerService = $containerService; } - public function run(bool $dryRun = true, bool $enableLogging = false, ?int $pid = null): array + public function run(bool $dryRun = true, bool $enableLogging = false, ?int $pid = null, ?int $languageId = null): array { $this->unsetContentDefenderConfiguration(); $dataHandler = GeneralUtility::makeInstance(DataHandler::class); @@ -65,7 +65,7 @@ public function run(bool $dryRun = true, bool $enableLogging = false, ?int $pid $containerUsedColPosArray[] = $column['colPos']; } } - $rows = $this->database->getNonContainerChildrenPerColPos($containerUsedColPosArray, $pid); + $rows = $this->database->getNonContainerChildrenPerColPos($containerUsedColPosArray, $pid, $languageId); foreach ($rows as $recordsPerPageAndColPos) { $prevSorting = 0; $prevContainer = null; @@ -73,13 +73,10 @@ public function run(bool $dryRun = true, bool $enableLogging = false, ?int $pid foreach ($recordsPerPageAndColPos as $record) { if (in_array($record['CType'], $cTypes, true)) { $container = $this->containerFactory->buildContainer($record['uid']); - $children = $container->getChildRecords(); - if (empty($children)) { - $sorting = $record['sorting']; - } else { - $lastChild = array_pop($children); - $sorting = $lastChild['sorting']; + $lastChild = $this->containerService->getAfterContainerRecord($container); + $sorting = $lastChild['sorting']; + if ($record['uid'] !== $lastChild['uid']) { if ($prevChild === null || $prevContainer === null) { $prevChild = $lastChild; $prevContainer = $container; diff --git a/Tests/Functional/Integrity/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_on_translated_page.csv b/Tests/Functional/Integrity/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_on_translated_page.csv new file mode 100644 index 00000000..148dbfe6 --- /dev/null +++ b/Tests/Functional/Integrity/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_on_translated_page.csv @@ -0,0 +1,15 @@ +"pages" +,"uid","pid","sys_language_uid" +,1,0,0 +,2,1,1 +,3,1,2 +"tt_content" +,"uid","pid","colPos","CType","sorting","tx_container_parent","sys_language_uid" +,1,2,0,"b13-2cols-with-header-container",1,,1 +,2,2,0,"b13-2cols-with-header-container",2,,1 +,3,2,202,,4,1,1 +,4,2,202,,3,2,1 +,5,3,0,"b13-2cols-with-header-container",5,,2 +,6,3,0,"b13-2cols-with-header-container",6,,2 +,7,3,202,,8,5,2 +,8,3,202,,7,6,2 diff --git a/Tests/Functional/Integrity/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_with_nested_changed_children_sorting.csv b/Tests/Functional/Integrity/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_with_nested_changed_children_sorting.csv new file mode 100644 index 00000000..08971172 --- /dev/null +++ b/Tests/Functional/Integrity/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_with_nested_changed_children_sorting.csv @@ -0,0 +1,10 @@ +"pages" +,"uid","pid" +,1,0 +"tt_content" +,"uid","pid","colPos","CType","sorting","tx_container_parent" +,1,1,0,b13-2cols-with-header-container,1, +,2,1,202,b13-2cols-with-header-container,2,1 +,3,1,202,,5,2 +,4,1,0,"b13-2cols-with-header-container",3, +,5,1,202,,4,4 diff --git a/Tests/Functional/Integrity/SortingInPageTest.php b/Tests/Functional/Integrity/SortingInPageTest.php index 406f22a9..38cbd5ee 100644 --- a/Tests/Functional/Integrity/SortingInPageTest.php +++ b/Tests/Functional/Integrity/SortingInPageTest.php @@ -65,6 +65,57 @@ public function containerIsSortedAfterChildOfPreviousContainer(): void self::assertTrue($rows[2]['sorting'] > $rows[3]['sorting'], 'container should be sorted after child of previous container'); } + public static function getPossibleTranslations(): iterable + { + yield 'with language id 1' => [ + 'languageId' => 1, + 'expected' => [ + 'errors' => 1, + 'sortings' => [ + 2 => 3, + ] + ] + ]; + yield 'with language id 2' => [ + 'languageId' => 2, + 'expected' => [ + 'errors' => 1, + 'sortings' => [ + 6 => 7, + ] + ] + ]; + yield 'with all languages' => [ + 'languageId' => null, + 'expected' => [ + 'errors' => 2, + 'sortings' => [ + 2 => 3, + 6 => 7, + ] + ] + ]; + } + + /** + * @test + * @dataProvider getPossibleTranslations + */ + public function containerIsSortedAfterChildOfPreviousContainerOnTranslatedPage(?int $languageId = null, array $expected): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_on_translated_page.csv'); + $errors = $this->sorting->run(false, false, null, 0); + self::assertTrue(count($errors) === 0, 'different number of errors for default language'); + + $errors = $this->sorting->run(false, false, null, $languageId); + self::assertTrue(count($errors) === $expected['errors'], 'different number of errors for given language'); + + $rows = $this->getContentsByUid(); + foreach ($expected['sortings'] as $before => $after) { + self::assertTrue($rows[$before]['sorting'] > $rows[$after]['sorting'], 'container should be sorted after child of previous container'); + } + } + /** * @test */ @@ -77,6 +128,19 @@ public function containerIsSortedAfterChildOfPreviousContainerWithChangedChildre self::assertTrue($rows[2]['sorting'] > $rows[3]['sorting'], 'container should be sorted after child of previous container'); } + /** + * @test + */ + public function containerIsSortedAfterChildOfPreviousContainerWithNestedChangedChildrenSorting(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/SortingInPage/container_is_sorted_before_child_of_previous_container_with_nested_changed_children_sorting.csv'); + $errors = $this->sorting->run(false); + self::assertTrue(count($errors) === 1, 'should get one error'); + $rows = $this->getContentsByUid(); + self::assertTrue($rows[4]['sorting'] > $rows[3]['sorting'], 'container should be sorted after last nested child of previous container'); + self::assertTrue($rows[5]['sorting'] > $rows[4]['sorting'], 'child should be sorted after its own parent container after resorting'); + } + /** * @test */