* All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ use WapplerSystems\Meilisearch\Domain\Index\Queue\RecordMonitor\Helper\RootPageResolver; use WapplerSystems\Meilisearch\FrontendEnvironment; use WapplerSystems\Meilisearch\System\Cache\TwoLevelCache; use WapplerSystems\Meilisearch\System\Configuration\ExtensionConfiguration; use WapplerSystems\Meilisearch\System\Records\Pages\PagesRepository; use WapplerSystems\Meilisearch\System\Util\SiteUtility; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Registry; use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\GeneralUtility; /** * SiteRepository * * Responsible to retrieve instances of Site objects * * @author Thomas Hohn */ class SiteRepository { /** * Rootpage resolver * * @var RootPageResolver */ protected $rootPageResolver; /** * @var TwoLevelCache */ protected $runtimeCache; /** * @var Registry */ protected $registry; /** * @var SiteFinder */ protected $siteFinder; /** * @var ExtensionConfiguration */ protected $extensionConfiguration; /** * @var FrontendEnvironment */ protected $frontendEnvironment = null; /** * SiteRepository constructor. * * @param RootPageResolver|null $rootPageResolver * @param TwoLevelCache|null $twoLevelCache * @param Registry|null $registry * @param SiteFinder|null $siteFinder * @param ExtensionConfiguration|null */ public function __construct( RootPageResolver $rootPageResolver = null, TwoLevelCache $twoLevelCache = null, Registry $registry = null, SiteFinder $siteFinder = null, ExtensionConfiguration $extensionConfiguration = null, FrontendEnvironment $frontendEnvironment = null ) { $this->rootPageResolver = $rootPageResolver ?? GeneralUtility::makeInstance(RootPageResolver::class); $this->runtimeCache = $twoLevelCache ?? GeneralUtility::makeInstance(TwoLevelCache::class, /** @scrutinizer ignore-type */'cache_runtime'); $this->registry = $registry ?? GeneralUtility::makeInstance(Registry::class); $this->siteFinder = $siteFinder ?? GeneralUtility::makeInstance(SiteFinder::class); $this->extensionConfiguration = $extensionConfiguration ?? GeneralUtility::makeInstance(ExtensionConfiguration::class); $this->frontendEnvironment = $frontendEnvironment ?? GeneralUtility::makeInstance(FrontendEnvironment::class); } /** * Gets the Site for a specific page Id. * * @param int $pageId The page Id to get a Site object for. * @param string $mountPointIdentifier * @return SiteInterface Site for the given page Id. */ public function getSiteByPageId($pageId, $mountPointIdentifier = '') { $rootPageId = $this->rootPageResolver->getRootPageId($pageId, false, $mountPointIdentifier); return $this->getSiteByRootPageId($rootPageId); } /** * Gets the Site for a specific root page Id. * * @param int $rootPageId Root page Id to get a Site object for. * @return SiteInterface Site for the given page Id. */ public function getSiteByRootPageId($rootPageId) { $cacheId = 'SiteRepository' . '_' . 'getSiteByPageId' . '_' . $rootPageId; $methodResult = $this->runtimeCache->get($cacheId); if (!empty($methodResult)) { return $methodResult; } $methodResult = $this->buildSite($rootPageId); $this->runtimeCache->set($cacheId, $methodResult); return $methodResult; } /** * Returns the first available Site. * * @param bool $stopOnInvalidSite * @throws \Exception * @return Site */ public function getFirstAvailableSite($stopOnInvalidSite = false) { $sites = $this->getAvailableSites($stopOnInvalidSite); return array_shift($sites); } /** * Gets all available TYPO3 sites with Meilisearch configured. * * @param bool $stopOnInvalidSite * @throws \Exception * @return Site[] An array of availablesites */ public function getAvailableSites($stopOnInvalidSite = false) { $cacheId = 'SiteRepository' . '_' . 'getAvailableSites'; $sites = $this->runtimeCache->get($cacheId); if (!empty($sites)) { return $sites; } $sites = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite); $this->runtimeCache->set($cacheId, $sites); return $sites; } /** * @param bool $stopOnInvalidSite * @return array * @throws \Exception */ protected function getAvailableTYPO3ManagedSites(bool $stopOnInvalidSite): array { $typo3ManagedMeilisearchSites = []; $typo3Sites = $this->siteFinder->getAllSites(); foreach ($typo3Sites as $typo3Site) { try { $rootPageId = $typo3Site->getRootPageId(); if (isset($typo3ManagedMeilisearchSites[$rootPageId])) { //get each site only once continue; } $typo3ManagedMeilisearchSite = $this->buildSite($rootPageId); if ($typo3ManagedMeilisearchSite->isEnabled()) { $typo3ManagedMeilisearchSites[$rootPageId] = $typo3ManagedMeilisearchSite; } } catch (\Exception $e) { if ($stopOnInvalidSite) { throw $e; } } } return $typo3ManagedMeilisearchSites; } /** * Creates an instance of the Site object. * * @param integer $rootPageId * @throws \InvalidArgumentException * @return SiteInterface */ protected function buildSite($rootPageId) { if (empty($rootPageId)) { throw new \InvalidArgumentException('Root page id can not be empty'); } $rootPageRecord = (array)BackendUtility::getRecord('pages', $rootPageId); $this->validateRootPageRecord($rootPageId, $rootPageRecord); return $this->buildTypo3ManagedSite($rootPageRecord); } /** * @param string $domain * @return string */ protected function getSiteHashForDomain($domain) { /** @var $siteHashService SiteHashService */ $siteHashService = GeneralUtility::makeInstance(SiteHashService::class); return $siteHashService->getSiteHashForDomain($domain); } /** * @param int $rootPageId * @param array $rootPageRecord * @throws \InvalidArgumentException */ protected function validateRootPageRecord($rootPageId, $rootPageRecord) { if (empty($rootPageRecord)) { throw new \InvalidArgumentException( 'The rootPageRecord for the given rootPageRecord ID \'' . $rootPageId . '\' could not be found in the database and can therefore not be used as site root rootPageRecord.', 1487326416 ); } if (!Site::isRootPage($rootPageRecord)) { throw new \InvalidArgumentException( 'The rootPageRecord for the given rootPageRecord ID \'' . $rootPageId . '\' is not marked as root rootPageRecord and can therefore not be used as site root rootPageRecord.', 1309272922 ); } } /** * @param array $rootPageRecord * @return Typo3ManagedSite */ protected function buildTypo3ManagedSite(array $rootPageRecord): ?Typo3ManagedSite { $meilisearchConfiguration = $this->frontendEnvironment->getMeilisearchConfigurationFromPageId($rootPageRecord['uid']); /** @var \TYPO3\CMS\Core\Site\Entity\Site $typo3Site */ try { $typo3Site = $this->siteFinder->getSiteByPageId($rootPageRecord['uid']); } catch (SiteNotFoundException $e) { return null; } $domain = $typo3Site->getBase()->getHost(); $siteHash = $this->getSiteHashForDomain($domain); $pageRepository = GeneralUtility::makeInstance(PagesRepository::class); $meilisearchConnectionConfiguration = []; $meilisearchEnabled = SiteUtility::getConnectionProperty($typo3Site, 'enabled', true); if ($meilisearchEnabled) { $meilisearchConnectionConfiguration = [ 'connectionKey' => $rootPageRecord['uid'] . '|', 'rootPageTitle' => $rootPageRecord['title'], 'rootPageUid' => $rootPageRecord['uid'], 'scheme' => SiteUtility::getConnectionProperty($typo3Site, 'scheme', 'http'), 'host' => SiteUtility::getConnectionProperty($typo3Site, 'host', 'localhost'), 'port' => (int)SiteUtility::getConnectionProperty($typo3Site, 'port',7700), 'apiKey' => SiteUtility::getConnectionProperty($typo3Site, 'apiKey', ''), ]; } return GeneralUtility::makeInstance( Typo3ManagedSite::class, /** @scrutinizer ignore-type */ $meilisearchConfiguration, /** @scrutinizer ignore-type */ $rootPageRecord, /** @scrutinizer ignore-type */ $domain, /** @scrutinizer ignore-type */ $siteHash, /** @scrutinizer ignore-type */ $pageRepository, /** @scrutinizer ignore-type */ $meilisearchConnectionConfiguration, /** @scrutinizer ignore-type */ $typo3Site ); } }