From e9ec9d0ba7d3fdeb8ad86d8bfdc7ae199583c5c0 Mon Sep 17 00:00:00 2001 From: Alexander Grein Date: Wed, 3 Jul 2024 12:26:38 +0200 Subject: [PATCH] Add getPageTsConfig to replace removed core method; Add getTypoScriptFrontendController to link modifier since method became protected in TYPO3 13 --- Classes/Middleware/JumpUrlHandler.php | 36 ++++++++++++++++++++--- Classes/TypoLink/LinkModifier.php | 42 ++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/Classes/Middleware/JumpUrlHandler.php b/Classes/Middleware/JumpUrlHandler.php index 0232c79..0ef1e46 100644 --- a/Classes/Middleware/JumpUrlHandler.php +++ b/Classes/Middleware/JumpUrlHandler.php @@ -19,12 +19,16 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Http\RedirectResponse; use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Resource\Security\FileNameValidator; +use TYPO3\CMS\Core\Site\Entity\NullSite; use TYPO3\CMS\Core\TimeTracker\TimeTracker; +use TYPO3\CMS\Core\TypoScript\PageTsConfig; +use TYPO3\CMS\Core\TypoScript\PageTsConfigFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; @@ -69,7 +73,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface } // Regular jump URL $this->validateIfJumpUrlRedirectIsAllowed($jumpUrl, $juHash); - return $this->redirectToJumpUrl($jumpUrl); + return $this->redirectToJumpUrl($jumpUrl, $request); } return $handler->handle($request); } @@ -81,9 +85,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface * @throws \Exception * @return ResponseInterface */ - protected function redirectToJumpUrl(string $jumpUrl): ResponseInterface + protected function redirectToJumpUrl(string $jumpUrl, ServerRequestInterface $request): ResponseInterface { - $pageTSconfig = $this->getTypoScriptFrontendController()->getPagesTSconfig(); + $pageTSconfig = $this->getPageTsConfig($request); $pageTSconfig = array_key_exists('TSFE.', $pageTSconfig) && is_array($pageTSconfig['TSFE.'] ?? false) ? $pageTSconfig['TSFE.'] : []; // Allow sections in links @@ -94,6 +98,30 @@ protected function redirectToJumpUrl(string $jumpUrl): ResponseInterface return new RedirectResponse($jumpUrl, $statusCode); } + /** + * @param ServerRequestInterface $request + * @return array + * @throws \JsonException + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException + */ + protected function getPageTsConfig(ServerRequestInterface $request): array + { + $pageInformation = $request->getAttribute('frontend.page.information'); + $id = $pageInformation->getId(); + $runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime'); + $pageTsConfig = $runtimeCache->get('pageTsConfig-' . $id); + if ($pageTsConfig instanceof PageTsConfig) { + return $pageTsConfig->getPageTsConfigArray(); + } + $fullRootLine = $pageInformation->getRootLine(); + ksort($fullRootLine); + $site = $request->getAttribute('site') ?? new NullSite(); + $pageTsConfigFactory = GeneralUtility::makeInstance(PageTsConfigFactory::class); + $pageTsConfig = $pageTsConfigFactory->create($fullRootLine, $site); + $runtimeCache->set('pageTsConfig-' . $id, $pageTsConfig); + return $pageTsConfig->getPageTsConfigArray(); + } + /** * If the submitted hash is correct and the user has access to the * related content element the contents of the submitted file will @@ -157,7 +185,7 @@ protected function forwardJumpUrlSecureFileData(string $jumpUrl, string $locatio protected function isLocationDataValid(string $locationData): bool { $isValidLocationData = false; - list($pageUid, $table, $recordUid) = explode(':', $locationData); + [$pageUid, $table, $recordUid] = explode(':', $locationData); $pageRepository = $this->getTypoScriptFrontendController()->sys_page; if (empty($table) || $pageRepository->checkRecord($table, $recordUid, true)) { // This check means that a record is checked only if the locationData has a value for a diff --git a/Classes/TypoLink/LinkModifier.php b/Classes/TypoLink/LinkModifier.php index a1ebc12..52b845e 100644 --- a/Classes/TypoLink/LinkModifier.php +++ b/Classes/TypoLink/LinkModifier.php @@ -17,6 +17,10 @@ use FoT3\Jumpurl\JumpUrlUtility; use TYPO3\CMS\Core\LinkHandling\LinkService; +use TYPO3\CMS\Core\Site\Entity\NullSite; +use TYPO3\CMS\Core\Site\Entity\Site; +use TYPO3\CMS\Core\Site\Entity\SiteLanguage; +use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\StringUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; @@ -36,12 +40,12 @@ class LinkModifier /** * @var TypoScriptFrontendController */ - protected $frontendController; + protected $typoScriptFrontendController; public function __invoke(AfterLinkIsGeneratedEvent $event): void { $this->contentObjectRenderer = $event->getContentObjectRenderer(); - $this->frontendController = $this->contentObjectRenderer->getTypoScriptFrontendController(); + $this->typoScriptFrontendController = $this->contentObjectRenderer->getTypoScriptFrontendController(); if ($this->isEnabled($event)) { $url = $event->getLinkResult()->getUrl(); @@ -192,13 +196,35 @@ protected function getTypoLinkParameter(array $configuration) protected function getTypoScriptFrontendController(): TypoScriptFrontendController { - $tsfe = $this->frontendController ?? $GLOBALS['TSFE'] ?? null; - if ($tsfe instanceof TypoScriptFrontendController) { - return $tsfe; + if ($this->typoScriptFrontendController instanceof TypoScriptFrontendController) { + return $this->typoScriptFrontendController; } - // workaround for getting a TSFE object in Backend - $linkBuilder = GeneralUtility::makeInstance(PageLinkBuilder::class, new ContentObjectRenderer()); - return $linkBuilder->getTypoScriptFrontendController(); + + // This usually happens when typolink is created by the TYPO3 Backend, where no TSFE object + // is there. This functionality is currently completely internal, as these links cannot be + // created properly from the Backend. + // However, this is added to avoid any exceptions when trying to create a link. + // Detecting the "first" site usually comes from the fact that TSFE needs to be instantiated + // during tests + $request = $this->contentObjectRenderer->getRequest(); + $site = $request->getAttribute('site'); + if (!$site instanceof Site) { + $sites = GeneralUtility::makeInstance(SiteFinder::class)->getAllSites(); + $site = reset($sites); + if (!$site instanceof Site) { + $site = new NullSite(); + } + } + $language = $request->getAttribute('language'); + if (!$language instanceof SiteLanguage) { + $language = $site->getDefaultLanguage(); + } + $request = $request->withAttribute('language', $language); + + $this->typoScriptFrontendController = GeneralUtility::makeInstance(TypoScriptFrontendController::class); + $this->typoScriptFrontendController->initializePageRenderer($request); + $this->typoScriptFrontendController->initializeLanguageService($request); + return $this->typoScriptFrontendController; } protected function getContentObjectRenderer(): ContentObjectRenderer