From aebc8b87f7247375cf682543528434a3cdb33f9f Mon Sep 17 00:00:00 2001 From: Stefan Froemken <froemken@gmail.com> Date: Mon, 27 Apr 2020 15:29:59 +0200 Subject: [PATCH] [BUGFIX] Cache various where clauses of PageRepository Since TYPO3 v9, PageRepository works independently from TSFE and can and should be instantiated on its own, depending on the context. This leads to multiple initializiation calls which can and should be cached, as a page with 100 links will re-trigger the properties all the time, even if they are not needed (groupWhereClause for instance). Caching these values reduces the time needed for typolink generation a lot. Resolves: #91208 Releases: master, 9.5 Change-Id: Ied7e2b78519754af2e10eeb4e9c1c9fcbbffe2e8 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64321 Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Benni Mack <benni@typo3.org> Tested-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Markus Klein <markus.klein@typo3.org> Reviewed-by: Benni Mack <benni@typo3.org> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> --- .../Domain/Repository/PageRepository.php | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php b/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php index 01db1b4e0724..aa7c252f078e 100644 --- a/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php +++ b/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php @@ -152,35 +152,42 @@ class PageRepository implements LoggerAwareInterface */ protected function init($show_hidden) { - $this->where_groupAccess = ''; - - $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages') - ->expr(); - if ($this->versioningWorkspaceId > 0) { - // For version previewing, make sure that enable-fields are not - // de-selecting hidden pages - we need versionOL() to unset them only - // if the overlay record instructs us to. - // Clear where_hid_del and restrict to live and current workspaces - $this->where_hid_del = ' AND ' . $expressionBuilder->andX( - $expressionBuilder->eq('pages.deleted', 0), - $expressionBuilder->orX( - $expressionBuilder->eq('pages.t3ver_wsid', 0), - $expressionBuilder->eq('pages.t3ver_wsid', (int)$this->versioningWorkspaceId) - ), - $expressionBuilder->neq('pages.doktype', self::DOKTYPE_RECYCLER) - ); + $cache = $this->getRuntimeCache(); + $cacheIdentifier = 'PageRepository_hidDelWhere' . ($show_hidden ? 'ShowHidden' : '') . '_' . (int)$this->versioningWorkspaceId; + $cacheEntry = $cache->get($cacheIdentifier); + if ($cacheEntry) { + $this->where_hid_del = $cacheEntry; } else { - // add starttime / endtime, and check for hidden/deleted - // Filter out new/deleted place-holder pages in case we are NOT in a - // versioning preview (that means we are online!) - $this->where_hid_del = ' AND ' . (string)$expressionBuilder->andX( - QueryHelper::stripLogicalOperatorPrefix( - $this->enableFields('pages', $show_hidden, ['fe_group' => true]) - ), - $expressionBuilder->neq('pages.doktype', self::DOKTYPE_RECYCLER) - ); + $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable('pages') + ->expr(); + if ($this->versioningWorkspaceId > 0) { + // For version previewing, make sure that enable-fields are not + // de-selecting hidden pages - we need versionOL() to unset them only + // if the overlay record instructs us to. + // Clear where_hid_del and restrict to live and current workspaces + $this->where_hid_del = ' AND ' . $expressionBuilder->andX( + $expressionBuilder->eq('pages.deleted', 0), + $expressionBuilder->orX( + $expressionBuilder->eq('pages.t3ver_wsid', 0), + $expressionBuilder->eq('pages.t3ver_wsid', (int)$this->versioningWorkspaceId) + ), + $expressionBuilder->neq('pages.doktype', self::DOKTYPE_RECYCLER) + ); + } else { + // add starttime / endtime, and check for hidden/deleted + // Filter out new/deleted place-holder pages in case we are NOT in a + // versioning preview (that means we are online!) + $this->where_hid_del = ' AND ' . (string)$expressionBuilder->andX( + QueryHelper::stripLogicalOperatorPrefix( + $this->enableFields('pages', $show_hidden, ['fe_group' => true]) + ), + $expressionBuilder->neq('pages.doktype', self::DOKTYPE_RECYCLER) + ); + } + $cache->set($cacheIdentifier, $this->where_hid_del); } + if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] ?? false)) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] as $classRef) { $hookObject = GeneralUtility::makeInstance($classRef); @@ -1377,6 +1384,12 @@ class PageRepository implements LoggerAwareInterface /** @var UserAspect $userAspect */ $userAspect = $this->context->getAspect('frontend.user'); $memberGroups = $userAspect->getGroupIds(); + $cache = $this->getRuntimeCache(); + $cacheIdentifier = 'PageRepository_groupAccessWhere_' . str_replace('.', '_', $field) . '_' . $table . '_' . implode('_', $memberGroups); + $cacheEntry = $cache->get($cacheIdentifier); + if ($cacheEntry) { + return $cacheEntry; + } $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable($table) @@ -1392,7 +1405,9 @@ class PageRepository implements LoggerAwareInterface $orChecks[] = $expressionBuilder->inSet($field, $expressionBuilder->literal($value)); } - return' AND (' . $expressionBuilder->orX(...$orChecks) . ')'; + $accessGroupWhere = ' AND (' . $expressionBuilder->orX(...$orChecks) . ')'; + $cache->set($cacheIdentifier, $accessGroupWhere); + return $accessGroupWhere; } /********************** -- GitLab