From d80e037f6663d531f00bdd339b420f015b2c93be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Fr=C3=B6mken?= Date: Thu, 12 Dec 2024 15:31:10 +0100 Subject: [PATCH] [FEATURE] Use PHP generator to prevent processing of all available site Use PHP generator with yield to process just the available sites needed How to test With over 300 root pages it needs over 30 seconds to build up all available sites. With help of a PHP generator we can stop processing all available sites if just the first site is requested. It's also helpful to just check, if there are available sites. This should speed up performance a lot. * Remove cache storing from methods of SiteRepository * Use hasAvailableSites in ModuleController * Remove cache-set check from tests for SiteRepository * Repair unit tests * Move check for duplicate sites to getAvailableSites. PhpStan * Remove unused imports Fixes: #3939 Ports: #4154 Replaces: #4145 --- .../Search/AbstractModuleController.php | 7 +- Classes/Domain/Site/SiteRepository.php | 78 +++++++++++++++---- Classes/Report/SiteHandlingStatus.php | 6 +- Classes/ViewHelpers/SearchFormViewHelper.php | 1 - Tests/Unit/Domain/Site/SiteRepositoryTest.php | 1 - 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Classes/Controller/Backend/Search/AbstractModuleController.php b/Classes/Controller/Backend/Search/AbstractModuleController.php index 14cbefb872..8a2b8c7900 100644 --- a/Classes/Controller/Backend/Search/AbstractModuleController.php +++ b/Classes/Controller/Backend/Search/AbstractModuleController.php @@ -125,9 +125,8 @@ protected function initializeAction(): void */ protected function autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable(): bool { - $solrConfiguredSites = $this->siteRepository->getAvailableSites(); $availableSites = $this->siteFinder->getAllSites(); - if (count($solrConfiguredSites) === 1 && count($availableSites) === 1) { + if (count($availableSites) === 1 && $this->siteRepository->hasExactlyOneAvailableSite()) { $this->selectedSite = $this->siteRepository->getFirstAvailableSite(); // we only overwrite the selected pageUid when no id was passed @@ -148,9 +147,7 @@ protected function autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable(): b */ protected function initializeView(ViewInterface|FluidStandaloneViewInterface $view): void { - $sites = $this->siteRepository->getAvailableSites(); - - $selectOtherPage = count($sites) > 0 || $this->selectedPageUID < 1; + $selectOtherPage = $this->siteRepository->hasAvailableSites() || $this->selectedPageUID < 1; $this->moduleTemplate->assign('showSelectOtherPage', $selectOtherPage); $this->moduleTemplate->assign('selectedPageUID', $this->selectedPageUID); if ($this->selectedPageUID < 1) { diff --git a/Classes/Domain/Site/SiteRepository.php b/Classes/Domain/Site/SiteRepository.php index 092f732430..c98a80a482 100644 --- a/Classes/Domain/Site/SiteRepository.php +++ b/Classes/Domain/Site/SiteRepository.php @@ -26,6 +26,7 @@ use ApacheSolrForTypo3\Solr\System\Records\Pages\PagesRepository; use ApacheSolrForTypo3\Solr\System\Util\SiteUtility; use Doctrine\DBAL\Exception as DBALException; +use Generator; use Throwable; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Exception\SiteNotFoundException; @@ -103,8 +104,12 @@ public function getSiteByRootPageId(int $rootPageId): ?Site */ public function getFirstAvailableSite(bool $stopOnInvalidSite = false): ?Site { - $sites = $this->getAvailableSites($stopOnInvalidSite); - return array_shift($sites); + $siteGenerator = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite); + $siteGenerator->rewind(); + + $site = $siteGenerator->current(); + + return $site instanceof Site ? $site : null; } /** @@ -119,37 +124,81 @@ public function getAvailableSites(bool $stopOnInvalidSite = false): array $cacheId = 'SiteRepository' . '_' . 'getAvailableSites'; $sites = $this->runtimeCache->get($cacheId); - if (!empty($sites)) { + if (is_array($sites) && $sites !== []) { return $sites; } - $sites = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite); + $siteGenerator = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite); + $siteGenerator->rewind(); + + $sites = []; + foreach ($siteGenerator as $rootPageId => $site) { + if (isset($sites[$rootPageId])) { + //get each site only once + continue; + } + $sites[$rootPageId] = $site; + } $this->runtimeCache->set($cacheId, $sites); return $sites; } + /** + * Check, if there are any managed sites available + * + * @throws UnexpectedTYPO3SiteInitializationException + */ + public function hasAvailableSites(bool $stopOnInvalidSite = false): bool + { + $siteGenerator = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite); + $siteGenerator->rewind(); + + return ($site = $siteGenerator->current()) && $site instanceof Site; + } + + /** + * Check, if there is exactly one managed site available + * Needed in AbstractModuleController::autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable + * + * @throws UnexpectedTYPO3SiteInitializationException + */ + public function hasExactlyOneAvailableSite(bool $stopOnInvalidSite = false): bool + { + if (!$this->hasAvailableSites($stopOnInvalidSite)) { + return false; + } + + $siteGenerator = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite); + $siteGenerator->rewind(); + + // We start with 1 here as we know from hasAvailableSites() above we have at least one site + $counter = 1; + foreach ($siteGenerator as $_) { + if ($counter > 1) { + return false; + } + $counter++; + } + + return true; + } + /** * Returns available TYPO3 sites * - * @return Site[] + * @return Site[]|Generator * * @throws UnexpectedTYPO3SiteInitializationException */ - protected function getAvailableTYPO3ManagedSites(bool $stopOnInvalidSite): array + protected function getAvailableTYPO3ManagedSites(bool $stopOnInvalidSite): Generator { - $typo3ManagedSolrSites = []; - $typo3Sites = $this->siteFinder->getAllSites(); - foreach ($typo3Sites as $typo3Site) { + foreach ($this->siteFinder->getAllSites() as $typo3Site) { try { $rootPageId = $typo3Site->getRootPageId(); - if (isset($typo3ManagedSolrSites[$rootPageId])) { - //get each site only once - continue; - } $typo3ManagedSolrSite = $this->buildSite($rootPageId); if ($typo3ManagedSolrSite->isEnabled()) { - $typo3ManagedSolrSites[$rootPageId] = $typo3ManagedSolrSite; + yield $rootPageId => $typo3ManagedSolrSite; } } catch (Throwable $e) { if ($stopOnInvalidSite) { @@ -161,7 +210,6 @@ protected function getAvailableTYPO3ManagedSites(bool $stopOnInvalidSite): array } } } - return $typo3ManagedSolrSites; } /** diff --git a/Classes/Report/SiteHandlingStatus.php b/Classes/Report/SiteHandlingStatus.php index 51f31585fa..bb2ee42da2 100644 --- a/Classes/Report/SiteHandlingStatus.php +++ b/Classes/Report/SiteHandlingStatus.php @@ -66,8 +66,7 @@ public function __construct( public function getStatus(): array { $reports = []; - $sites = $this->siteRepository->getAvailableSites(); - if (empty($sites)) { + if (!$this->siteRepository->hasAvailableSites()) { $reports[] = GeneralUtility::makeInstance( Status::class, self::TITLE_SITE_HANDLING_CONFIGURATION, @@ -79,8 +78,7 @@ public function getStatus(): array return $reports; } - /** @var Site $site */ - foreach ($sites as $site) { + foreach ($this->siteRepository->getAvailableSites() as $site) { if (!($site instanceof Site)) { $reports[] = GeneralUtility::makeInstance( Status::class, diff --git a/Classes/ViewHelpers/SearchFormViewHelper.php b/Classes/ViewHelpers/SearchFormViewHelper.php index 8334b32d3a..8a564570a9 100644 --- a/Classes/ViewHelpers/SearchFormViewHelper.php +++ b/Classes/ViewHelpers/SearchFormViewHelper.php @@ -30,7 +30,6 @@ /** * Class SearchFormViewHelper * - * * @property RenderingContext $renderingContext */ class SearchFormViewHelper extends AbstractSolrFrontendTagBasedViewHelper diff --git a/Tests/Unit/Domain/Site/SiteRepositoryTest.php b/Tests/Unit/Domain/Site/SiteRepositoryTest.php index 254919bed4..aa127c06f5 100644 --- a/Tests/Unit/Domain/Site/SiteRepositoryTest.php +++ b/Tests/Unit/Domain/Site/SiteRepositoryTest.php @@ -89,7 +89,6 @@ public function canGetFirstAvailableSite(): void $this->assertThatSitesAreCreatedWithPageIds([333], [ 0 => ['language' => 0], ]); - $this->assertCacheIsWritten(); $site = $this->siteRepository->getFirstAvailableSite(); self::assertInstanceOf(Site::class, $site);