From da5540f7b6fbfad6bf414302628270c515633a41 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 7 Jun 2024 15:21:09 +0200 Subject: [PATCH] [BUGFIX] Mitigate unrelated page traversal for glossary lookup Based on the concept the matching glossaries for the current site root tree should be used for translation process. Glossaries are managed on default pages with the `glossaries` module attached, thus are free to be defined within the page tree structure. Using a page traversal approach from the detected site root becomes really costly as it traverse the full page tree beneath the matched site root, thus becoming quickly quite costly. Albeit not the best approach, retrieving pages with the module attached and using the SiteFinder and therefore the rootline to sort out module pages not included for the site root reduces the traversed and retrieved pages white a lot. Note: With dropping TYPO3 v12 support it would be possible to use handcrafted common table expressions to further optimize that lookup and with TYPO3 v13 at least TYPO3 Core internal API may be available. This change modifies the glossary id lookup method to exchange the pagetraversal approach with a flat record list rootline check approach as a first, quick and non breaking improvement. Instances not using the glossary feature avoids the recursive traversal at all with this implementation. --- Build/phpstan/Core11/phpstan-baseline.neon | 5 +++ Build/phpstan/Core12/phpstan-baseline.neon | 5 +++ .../Domain/Repository/GlossaryRepository.php | 40 +++++++++++++------ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Build/phpstan/Core11/phpstan-baseline.neon b/Build/phpstan/Core11/phpstan-baseline.neon index 91357e56..c20e2b2c 100644 --- a/Build/phpstan/Core11/phpstan-baseline.neon +++ b/Build/phpstan/Core11/phpstan-baseline.neon @@ -235,6 +235,11 @@ parameters: count: 1 path: ../../../Classes/Utility/HtmlUtility.php + - + message: "#^Parameter \\#2 \\$length of function fread expects int\\<1, max\\>, int\\<0, max\\> given\\.$#" + count: 1 + path: ../../../Tests/Functional/AbstractDeepLTestCase.php + - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Tests\\\\Functional\\\\Fixtures\\\\Frontend\\\\PhpError\\:\\:__construct\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#" count: 1 diff --git a/Build/phpstan/Core12/phpstan-baseline.neon b/Build/phpstan/Core12/phpstan-baseline.neon index 5a3e531b..4bbc2824 100644 --- a/Build/phpstan/Core12/phpstan-baseline.neon +++ b/Build/phpstan/Core12/phpstan-baseline.neon @@ -235,6 +235,11 @@ parameters: count: 1 path: ../../../Classes/Utility/HtmlUtility.php + - + message: "#^Parameter \\#2 \\$length of function fread expects int\\<1, max\\>, int\\<0, max\\> given\\.$#" + count: 1 + path: ../../../Tests/Functional/AbstractDeepLTestCase.php + - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Tests\\\\Functional\\\\Fixtures\\\\Frontend\\\\PhpError\\:\\:__construct\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#" count: 1 diff --git a/Classes/Domain/Repository/GlossaryRepository.php b/Classes/Domain/Repository/GlossaryRepository.php index fbef837c..a040558b 100644 --- a/Classes/Domain/Repository/GlossaryRepository.php +++ b/Classes/Domain/Repository/GlossaryRepository.php @@ -11,6 +11,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\SiteFinder; @@ -470,33 +471,48 @@ private function getGlossary( */ private function getGlossariesInRootByCurrentPage(int $pageId): array { - $site = GeneralUtility::makeInstance(SiteFinder::class) - ->getSiteByPageId($pageId); - $rootPage = $site->getRootPageId(); - $allPages = GeneralUtility::makeInstance(PageTreeRepository::class) - ->getTreeList($rootPage, 999); $db = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('pages'); - $statement = $db + + $result = $db ->select('uid') ->from('pages') ->where( - $db->expr()->in('uid', $allPages), - $db->expr()->eq('doktype', $db->createNamedParameter(254, Connection::PARAM_INT)), + $db->expr()->eq( + 'doktype', + $db->createNamedParameter( + PageRepository::DOKTYPE_SYSFOLDER, + Connection::PARAM_INT + ) + ), $db->expr()->eq('module', $db->createNamedParameter('glossary')) - ); - $result = $statement->executeQuery()->fetchAllAssociative(); + )->executeQuery(); - if (!is_array($result)) { + $rows = $result->fetchAllAssociative(); + if (count($rows) === 0) { return []; } + + $rootPage = $this->findRootPageId($pageId); + $ids = []; - foreach ($result as $row) { + foreach ($rows as $row) { + $glossaryRootPageID = $this->findRootPageId($row['uid']); + if ($glossaryRootPageID !== $rootPage) { + continue; + } + $ids[] = $row['uid']; } return $ids; } + private function findRootPageId(int $pageId): int + { + $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageId); + return $site->getRootPageId(); + } + public function setGlossaryNotSyncOnPage(int $pageId): void { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)