diff --git a/Classes/System/Records/SystemTemplate/SystemTemplateRepository.php b/Classes/System/Records/SystemTemplate/SystemTemplateRepository.php index 02aead3c6..857bd920b 100644 --- a/Classes/System/Records/SystemTemplate/SystemTemplateRepository.php +++ b/Classes/System/Records/SystemTemplate/SystemTemplateRepository.php @@ -18,6 +18,7 @@ namespace ApacheSolrForTypo3\Solr\System\Records\SystemTemplate; use ApacheSolrForTypo3\Solr\System\Records\AbstractRepository; +use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Exception as DBALException; /** @@ -34,23 +35,78 @@ class SystemTemplateRepository extends AbstractRepository * @throws DBALException */ public function findOneClosestPageIdWithActiveTemplateByRootLine(array $rootLine): ?int + { + if (empty($rootLine)) { + return null; + } + + [$rootLinePageIds, $rootLinePositions] = $this->extractPageIdsAndPositions($rootLine); + $templateRecords = $this->getTemplateRecordsFromRootlinePages($rootLinePageIds); + + if (empty($templateRecords)) { + return null; + } + + $this->sortTemplateRecordsByPageRootlinePosition($templateRecords, $rootLinePositions); + + return isset($templateRecords[0]['pid']) ? (int)$templateRecords[0]['pid'] : null; + } + + /** + * @param array $rootLine + * @return array{0: list, 1: array} + */ + protected function extractPageIdsAndPositions(array $rootLine): array { $rootLinePageIds = [0]; - foreach ($rootLine as $rootLineItem) { - $rootLinePageIds[] = (int)$rootLineItem['uid']; + $rootLinePositions = []; + + foreach ($rootLine as $position => $rootLineItem) { + $pageId = (int)$rootLineItem['uid']; + $rootLinePageIds[] = $pageId; + $rootLinePositions[$pageId] = $position; } + return [$rootLinePageIds, $rootLinePositions]; + } + + /** + * Retrieves template records associated with the given page IDs from the rootline. + * + * @param list $rootLinePageIds The page IDs from the rootline to search for templates on. + * @return list A list of template records (uid, pid) found, or an empty list if none are found. + * @throws DBALException + */ + protected function getTemplateRecordsFromRootlinePages(array $rootLinePageIds): array + { $queryBuilder = $this->getQueryBuilder(); $result = $queryBuilder ->select('uid', 'pid') ->from($this->table) ->where( - $queryBuilder->expr()->in('pid', $rootLinePageIds) + $queryBuilder->expr()->in( + 'pid', + $queryBuilder->createNamedParameter( + $rootLinePageIds, + ArrayParameterType::INTEGER + ) + ) ) ->executeQuery() - ->fetchAssociative(); + ->fetchAllAssociative(); - return $result['pid'] ?? null; + return $result ?: []; + } + + /** + * Sorts template records based on the rootline position of the page they belong to. + * + * @param list $templateRecords The template records to sort. + * @param array $pageRootlinePositions A map of page IDs to their rootline positions. + */ + protected function sortTemplateRecordsByPageRootlinePosition(array &$templateRecords, array $pageRootlinePositions): void + { + usort($templateRecords, static fn(array $a, array $b): int => $pageRootlinePositions[$b['pid']] <=> $pageRootlinePositions[$a['pid']]); } } diff --git a/Tests/Integration/System/Records/SystemTemplate/Fixtures/sys_template.csv b/Tests/Integration/System/Records/SystemTemplate/Fixtures/sys_template.csv index 9056f05d2..209f65dd5 100644 --- a/Tests/Integration/System/Records/SystemTemplate/Fixtures/sys_template.csv +++ b/Tests/Integration/System/Records/SystemTemplate/Fixtures/sys_template.csv @@ -1,3 +1,4 @@ "sys_template", ,"uid","pid","root","sorting","config" ,777,33,1,100,"page = PAGE" +,778,44,1,200,"page = PAGE" diff --git a/Tests/Integration/System/Records/SystemTemplate/SystemTemplateRepositoryTest.php b/Tests/Integration/System/Records/SystemTemplate/SystemTemplateRepositoryTest.php index c7954605f..7a2badda7 100644 --- a/Tests/Integration/System/Records/SystemTemplate/SystemTemplateRepositoryTest.php +++ b/Tests/Integration/System/Records/SystemTemplate/SystemTemplateRepositoryTest.php @@ -17,6 +17,7 @@ use ApacheSolrForTypo3\Solr\System\Records\SystemTemplate\SystemTemplateRepository; use ApacheSolrForTypo3\Solr\Tests\Integration\IntegrationTestBase; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -25,20 +26,61 @@ */ class SystemTemplateRepositoryTest extends IntegrationTestBase { + public static function rootLineDataProvider(): array + { + return [ + 'Rootline with template on page 33 (2nd)' => [ + [ + ['uid' => 4], // No template + ['uid' => 3], // No template + ['uid' => 2], // No template + ['uid' => 33], // Template here + ['uid' => 1], // Current page + ], + 33, + ], + 'Rootline with template on page 44 (2nd)' => [ + [ + ['uid' => 5], // No template + ['uid' => 33], // Template here, but 44 is closer + ['uid' => 2], // No template + ['uid' => 44], // Template here + ['uid' => 1], // Current page + ], + 44, + ], + 'Rootline with template on page 33 (3rd), page 44 (5th)' => [ + [ + ['uid' => 44], // Template here, but 33 is closer + ['uid' => 30], // No template + ['uid' => 33], // Template here + ['uid' => 20], // No template + ['uid' => 10], // Current page + ], + 33, + ], + 'Rootline with template on page 44 (3rd), page 33 (5th)' => [ + [ + ['uid' => 33], // Template here, but 44 is closer + ['uid' => 30], // No template + ['uid' => 44], // Template here + ['uid' => 20], // No template + ['uid' => 10], // Current page + ], + 44, + ], + ]; + } + + #[DataProvider('rootLineDataProvider')] #[Test] - public function canFindOneClosestPageIdWithActiveTemplateByRootLine(): void + public function canFindOneClosestPageIdWithActiveTemplateByRootLine(array $fakeRootLine, int $expectedPageId): void { $this->importCSVDataSet(__DIR__ . '/Fixtures/sys_template.csv'); - $fakeRootLine = [ - ['uid' => 100], - ['uid' => 33], - ['uid' => 8657], - ]; - /** @var SystemTemplateRepository $repository */ $repository = GeneralUtility::makeInstance(SystemTemplateRepository::class); $closestPageIdWithActiveTemplate = $repository->findOneClosestPageIdWithActiveTemplateByRootLine($fakeRootLine); - self::assertEquals(33, $closestPageIdWithActiveTemplate, 'Can not find closest page id with active template.'); + self::assertEquals($expectedPageId, $closestPageIdWithActiveTemplate, 'Can not find closest page id with active template.'); } }