diff --git a/typo3/sysext/adminpanel/Classes/Modules/Info/GeneralInformation.php b/typo3/sysext/adminpanel/Classes/Modules/Info/GeneralInformation.php index c3f0c0f51c343d26dbd7cb919e377abe24d8b651..7f1f5700c9820826de541aadf489af0bee881517 100644 --- a/typo3/sysext/adminpanel/Classes/Modules/Info/GeneralInformation.php +++ b/typo3/sysext/adminpanel/Classes/Modules/Info/GeneralInformation.php @@ -22,27 +22,28 @@ use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule; use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface; use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData; use TYPO3\CMS\Core\Context\Context; -use TYPO3\CMS\Core\Context\UserAspect; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Page\AssetCollector; use TYPO3\CMS\Core\TimeTracker\TimeTracker; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Fluid\View\StandaloneView; -use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; /** - * General information module displaying info about the current - * request + * General information module displaying info about the current request * * @internal */ class GeneralInformation extends AbstractSubModule implements DataProviderInterface { + public function __construct( + private readonly TimeTracker $timeTracker, + private readonly Context $context, + ) {} + public function getDataToStore(ServerRequestInterface $request): ModuleData { - /** @var UserAspect $frontendUserAspect */ - $frontendUserAspect = GeneralUtility::makeInstance(Context::class)->getAspect('frontend.user'); - $tsfe = $this->getTypoScriptFrontendController(); + $frontendUserAspect = $this->context->getAspect('frontend.user'); + $tsfe = $request->getAttribute('frontend.controller'); return new ModuleData( [ 'post' => $request->getParsedBody(), @@ -56,7 +57,7 @@ class GeneralInformation extends AbstractSubModule implements DataProviderInterf 'noCache' => !$this->isCachingAllowed($request), 'noCacheReasons' => $request->getAttribute('frontend.cache.instruction')->getDisabledCacheReasons(), 'countUserInt' => count($tsfe->config['INTincScript'] ?? []), - 'totalParsetime' => $this->getTimeTracker()->getParseTime(), + 'totalParsetime' => $this->timeTracker->getParseTime(), 'feUser' => [ 'uid' => $frontendUserAspect->get('id') ?: 0, 'username' => $frontendUserAspect->get('username') ?: '', @@ -145,7 +146,8 @@ class GeneralInformation extends AbstractSubModule implements DataProviderInterf { $documentSize = 0; if (!$this->isCachingAllowed($request)) { - $documentSize = mb_strlen($this->getTypoScriptFrontendController()->content, 'UTF-8'); + $tsfe = $request->getAttribute('frontend.controller'); + $documentSize = mb_strlen($tsfe->content, 'UTF-8'); } return GeneralUtility::formatSize($documentSize); } @@ -154,14 +156,4 @@ class GeneralInformation extends AbstractSubModule implements DataProviderInterf { return $request->getAttribute('frontend.cache.instruction')->isCachingAllowed(); } - - protected function getTypoScriptFrontendController(): TypoScriptFrontendController - { - return $GLOBALS['TSFE']; - } - - protected function getTimeTracker(): TimeTracker - { - return GeneralUtility::makeInstance(TimeTracker::class); - } } diff --git a/typo3/sysext/adminpanel/Configuration/Services.yaml b/typo3/sysext/adminpanel/Configuration/Services.yaml index 23980b6a0b9d2f22a84191ea2220a848e66bfe90..cca02b9dd6c13da9c4b247ed0c335bf0ac2fb3f9 100644 --- a/typo3/sysext/adminpanel/Configuration/Services.yaml +++ b/typo3/sysext/adminpanel/Configuration/Services.yaml @@ -31,6 +31,8 @@ services: public: true TYPO3\CMS\Adminpanel\Modules\Debug\Events: public: true + TYPO3\CMS\Adminpanel\Modules\Info\GeneralInformation: + public: true TYPO3\CMS\Adminpanel\Modules\TsDebug\TypoScriptWaterfall: public: true diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php index cf561829dabc2c1811d969f4a4e198a4d7dde0bd..ae52e4319faac4ca1fff175110715388de28b62f 100644 --- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php +++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php @@ -26,7 +26,6 @@ use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend; use TYPO3\CMS\Core\Context\Context; -use TYPO3\CMS\Core\Context\UserAspect; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Domain\Repository\PageRepository; @@ -142,11 +141,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface */ public ?PageRepository $sys_page = null; - /** - * @internal - */ - public string $MP = ''; - /** * A central data array consisting of various keys, initialized and * processed at various places in the class. @@ -336,6 +330,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface */ public function __construct(Context $context, Site $site, SiteLanguage $siteLanguage, PageArguments $pageArguments) { + $this->sys_page = GeneralUtility::makeInstance(PageRepository::class); $this->context = $context; $this->site = $site; $this->language = $siteLanguage; @@ -614,7 +609,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface // constant condition verdicts, the setup condition verdicts, plus various not TypoScript related details like // obviously the page id. $this->lock = GeneralUtility::makeInstance(ResourceMutex::class); - $this->newHash = $this->createHashBase($sysTemplateRows, $constantConditionList, $setupConditionList); + $this->newHash = $this->createHashBase($request, $sysTemplateRows, $constantConditionList, $setupConditionList); if ($isCachingAllowed) { if ($this->shouldAcquireCacheData($request)) { // Try to get a page cache row. @@ -731,7 +726,9 @@ class TypoScriptFrontendController implements LoggerAwareInterface } } - $type = (int)($this->pageArguments->getPageType() ?: 0); + /** @var PageArguments $pageArguments */ + $pageArguments = $request->getAttribute('routing'); + $type = (int)($pageArguments->getPageType() ?: 0); $typoScriptPageTypeName = $setupArray['types.'][$type] ?? ''; $typoScriptPageTypeSetup = $setupArray[$typoScriptPageTypeName . '.'] ?? null; if (!is_array($typoScriptPageTypeSetup)) { @@ -849,28 +846,31 @@ class TypoScriptFrontendController implements LoggerAwareInterface * the other requests wait until this finished and re-use the result. * * This hash is unique to the TS template and constant and setup condition verdict, - * the variables ->id, ->type, list of frontend user groups, ->MP (Mount Points) and cHash array. + * the variables ->id, ->type, list of frontend user groups, mount points and cHash array. * * @return string Page cache entry identifier also used as page generation lock */ - protected function createHashBase(array $sysTemplateRows, array $constantConditionList, array $setupConditionList): string + protected function createHashBase(ServerRequestInterface $request, array $sysTemplateRows, array $constantConditionList, array $setupConditionList): string { // Fetch the list of user groups - /** @var UserAspect $userAspect */ $userAspect = $this->context->getAspect('frontend.user'); + $pageInformation = $request->getAttribute('frontend.page.information'); + $site = $request->getAttribute('site'); + $language = $request->getAttribute('language', $site->getDefaultLanguage()); + $pageArguments = $request->getAttribute('routing'); $hashParameters = [ - 'id' => $this->id, - 'type' => (int)($this->pageArguments->getPageType() ?: 0), - 'groupIds' => (string)implode(',', $userAspect->getGroupIds()), - 'MP' => (string)$this->MP, - 'site' => $this->site->getIdentifier(), + 'id' => $pageInformation->getId(), + 'type' => (int)($pageArguments->getPageType() ?: 0), + 'groupIds' => implode(',', $userAspect->getGroupIds()), + 'MP' => $pageInformation->getMountPoint(), + 'site' => $site->getIdentifier(), // Ensure the language base is used for the hash base calculation as well, otherwise TypoScript and page-related rendering // is not cached properly as we don't have any language-specific conditions anymore - 'siteBase' => (string)$this->language->getBase(), + 'siteBase' => (string)$language->getBase(), // additional variation trigger for static routes - 'staticRouteArguments' => $this->pageArguments->getStaticArguments(), + 'staticRouteArguments' => $pageArguments->getStaticArguments(), // dynamic route arguments (if route was resolved) - 'dynamicArguments' => $this->getRelevantParametersForCachingFromPageArguments($this->pageArguments), + 'dynamicArguments' => $this->getRelevantParametersForCachingFromPageArguments($pageArguments), 'sysTemplateRows' => $sysTemplateRows, 'constantConditionList' => $constantConditionList, 'setupConditionList' => $setupConditionList, diff --git a/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php b/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php index 58bbe180c1f2dd6f96629d40511675827137886f..6d48184548eb2ee6c234af9e5077207ef2899d29 100644 --- a/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php +++ b/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php @@ -143,9 +143,7 @@ final class TypoScriptFrontendInitialization implements MiddlewareInterface ); // b/w compat layer $controller->id = $pageInformation->getId(); - $controller->sys_page = GeneralUtility::makeInstance(PageRepository::class); $controller->page = $pageInformation->getPageRecord(); - $controller->MP = $pageInformation->getMountPoint(); $controller->contentPid = $pageInformation->getContentFromPid(); $controller->rootLine = $pageInformation->getRootLine(); diff --git a/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php b/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php index 7bb855057bef431c72add7f100eec154d541cd5e..765d964c1055b13c2a6c5a85377380e89cea6987 100644 --- a/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php +++ b/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php @@ -576,22 +576,24 @@ class PageLinkBuilder extends AbstractTypolinkBuilder */ protected function getClosestMountPointValueForPage(int $pageId): string { - $tsfe = $this->getTypoScriptFrontendController(); - if (empty($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) || !$tsfe->MP) { + $request = $this->contentObjectRenderer->getRequest(); + $mountPoint = $request->getAttribute('frontend.page.information')?->getMountPoint() ?? ''; + if (empty($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) || !$mountPoint) { return ''; } // Same page as current. - if ($tsfe->id === $pageId) { - return $tsfe->MP; + if (($request->getAttribute('frontend.page.information')?->getId() ?? 0) === $pageId) { + return $mountPoint; } - // Find closest mount point + // Find the closest mount point // Gets rootline of linked-to page try { $tCR_rootline = GeneralUtility::makeInstance(RootlineUtility::class, $pageId)->get(); - } catch (RootLineException $e) { + } catch (RootLineException) { $tCR_rootline = []; } + $tsfe = $this->getTypoScriptFrontendController(); $inverseLocalRootLine = array_reverse($tsfe->config['rootLine'] ?? []); $rl_mpArray = []; $startMPaccu = false; diff --git a/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/PageExposingTsfeMpParameter.typoscript b/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/PageExposingTsfeMpParameter.typoscript deleted file mode 100644 index e4095aabffafd40dc051e5b314fe05b9b66da51d..0000000000000000000000000000000000000000 --- a/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/PageExposingTsfeMpParameter.typoscript +++ /dev/null @@ -1,3 +0,0 @@ -page = PAGE -page.10 = USER_INT -page.10.userFunc = TYPO3\CMS\Frontend\Tests\Functional\Controller\Fixtures\TypoScriptFrontendControllerTestUserFuncs->pageExposingMpParameterUserInt diff --git a/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/PageHelloWorld.typoscript b/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/PageHelloWorld.typoscript new file mode 100644 index 0000000000000000000000000000000000000000..87ad609dfc1e04715bf8c6fc3af1bed26849e29f --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/PageHelloWorld.typoscript @@ -0,0 +1,3 @@ +page = PAGE +page.10 = TEXT +page.10.value = Hello world diff --git a/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/TypoScriptFrontendControllerTestUserFuncs.php b/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/TypoScriptFrontendControllerTestUserFuncs.php index a9d8322385939a8ddba630bcd798a22f138256a1..b895637e53ae12c17102d47a2877afbb2aeb539e 100644 --- a/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/TypoScriptFrontendControllerTestUserFuncs.php +++ b/typo3/sysext/frontend/Tests/Functional/Controller/Fixtures/TypoScriptFrontendControllerTestUserFuncs.php @@ -44,15 +44,4 @@ final class TypoScriptFrontendControllerTestUserFuncs { return $GLOBALS['TSFE']->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:mod_tx_cms_webinfo_page'); } - - /** - * A USER_INT method referenced in PageExposingTsfeMpParameter.typoscript - */ - public function pageExposingMpParameterUserInt(): string - { - if ($GLOBALS['TSFE']->MP === '') { - return 'empty'; - } - return 'foo' . $GLOBALS['TSFE']->MP . 'bar'; - } } diff --git a/typo3/sysext/frontend/Tests/Functional/Controller/TypoScriptFrontendControllerTest.php b/typo3/sysext/frontend/Tests/Functional/Controller/TypoScriptFrontendControllerTest.php index fa0ba641d6114a75829dc4134de265a8c22a560d..e024b56afb96b0ec3650af48863e7df617c5ba40 100644 --- a/typo3/sysext/frontend/Tests/Functional/Controller/TypoScriptFrontendControllerTest.php +++ b/typo3/sysext/frontend/Tests/Functional/Controller/TypoScriptFrontendControllerTest.php @@ -160,50 +160,6 @@ alert(yes);', $body); self::assertStringContainsString('Pagetree Overview', $body); } - public static function mountPointParameterContainsOnlyValidMPValuesDataProvider(): array - { - return [ - 'no MP Parameter given' => [ - '', - 'empty', - ], - 'single MP parameter given' => [ - '592-182', - 'foo592-182bar', - ], - 'invalid characters included' => [ - '12-13,a34-45/', - 'foo12-13,34-45bar', - ], - ]; - } - - /** - * @test - * @dataProvider mountPointParameterContainsOnlyValidMPValuesDataProvider - */ - public function mountPointParameterContainsOnlyValidMPValues(string $inputMp, string $expected): void - { - $this->importCSVDataSet(__DIR__ . '/DataSet/LiveDefaultPages.csv'); - $this->setUpFrontendRootPage( - 2, - ['EXT:frontend/Tests/Functional/Controller/Fixtures/PageExposingTsfeMpParameter.typoscript'] - ); - $this->writeSiteConfiguration( - 'test', - $this->buildSiteConfiguration(2, 'https://website.local/'), - [$this->buildDefaultLanguageConfiguration('EN', '/en/')] - ); - - $response = $this->executeFrontendSubRequest( - (new InternalRequest('https://website.local/en/')) - ->withPageId(88) - ->withQueryParameter('MP', $inputMp) - ); - $body = (string)$response->getBody(); - self::assertStringContainsString($expected, $body); - } - public static function getFromCacheSetsConfigRootlineToLocalRootlineDataProvider(): array { $page1 = [ @@ -381,7 +337,7 @@ alert(yes);', $body); $this->importCSVDataSet(__DIR__ . '/DataSet/LiveDefaultPages.csv'); $this->setUpFrontendRootPage( 2, - ['EXT:frontend/Tests/Functional/Controller/Fixtures/PageExposingTsfeMpParameter.typoscript'] + ['EXT:frontend/Tests/Functional/Controller/Fixtures/PageHelloWorld.typoscript'] ); $this->writeSiteConfiguration( 'test', diff --git a/typo3/sysext/indexed_search/Classes/EventListener/FrontendGenerationPageIndexingTrigger.php b/typo3/sysext/indexed_search/Classes/EventListener/FrontendGenerationPageIndexingTrigger.php index f4f2b5c14ca8cb203c1951adc27f9cf150a98c1b..75b97c92bf72fe098e40b67fbcff0ee32feec728 100644 --- a/typo3/sysext/indexed_search/Classes/EventListener/FrontendGenerationPageIndexingTrigger.php +++ b/typo3/sysext/indexed_search/Classes/EventListener/FrontendGenerationPageIndexingTrigger.php @@ -18,11 +18,13 @@ declare(strict_types=1); namespace TYPO3\CMS\IndexedSearch\EventListener; use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Core\Attribute\AsEventListener; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Context\LanguageAspect; use TYPO3\CMS\Core\PageTitle\PageTitleProviderManager; +use TYPO3\CMS\Core\Routing\PageArguments; use TYPO3\CMS\Core\TimeTracker\TimeTracker; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\CMS\Frontend\Event\AfterCacheableContentIsGeneratedEvent; @@ -83,7 +85,7 @@ class FrontendGenerationPageIndexingTrigger } // Init and start indexing $this->indexer->forceIndexing = $forceIndexing; - $this->indexer->init($this->initializeIndexerConfiguration($tsfe, $languageAspect)); + $this->indexer->init($this->initializeIndexerConfiguration($event->getRequest(), $tsfe, $languageAspect)); $this->indexer->indexTypo3PageContent(); $this->timeTracker->pull(); } @@ -92,24 +94,26 @@ class FrontendGenerationPageIndexingTrigger * Setting up internal configuration from config array based on TypoScriptFrontendController * Information about page for which the indexing takes place */ - protected function initializeIndexerConfiguration(TypoScriptFrontendController $tsfe, LanguageAspect $languageAspect): array + protected function initializeIndexerConfiguration(ServerRequestInterface $request, TypoScriptFrontendController $tsfe, LanguageAspect $languageAspect): array { - $pageArguments = $tsfe->getPageArguments(); + /** @var PageArguments $pageArguments */ + $pageArguments = $request->getAttribute('routing'); + $pageInformation = $request->getAttribute('frontend.page.information'); $configuration = [ // Page id - 'id' => $tsfe->id, + 'id' => $pageInformation->getId(), // Page type 'type' => $pageArguments->getPageType(), // site language id of the language of the indexing. 'sys_language_uid' => $languageAspect->getId(), // MP variable, if any (Mount Points) - 'MP' => $tsfe->MP, + 'MP' => $pageInformation->getMountPoint(), // Group list 'gr_list' => implode(',', $this->context->getPropertyFromAspect('frontend.user', 'groupIds', [0, -1])), // page arguments array 'staticPageArguments' => $pageArguments->getStaticArguments(), // The creation date of the TYPO3 page - 'crdate' => $tsfe->page['crdate'], + 'crdate' => $pageInformation->getPageRecord()['crdate'], 'rootline_uids' => [], ]; diff --git a/typo3/sysext/redirects/Classes/Service/RedirectService.php b/typo3/sysext/redirects/Classes/Service/RedirectService.php index 368a3b5007fa27c3c5460cf54638050423194b38..48a15e8d2aa89ee2fce2a80339dde290ae5d1adf 100644 --- a/typo3/sysext/redirects/Classes/Service/RedirectService.php +++ b/typo3/sysext/redirects/Classes/Service/RedirectService.php @@ -23,7 +23,6 @@ use Psr\Http\Message\UriInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use TYPO3\CMS\Core\Context\Context; -use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Http\Uri; use TYPO3\CMS\Core\LinkHandling\LinkService; @@ -395,6 +394,7 @@ class RedirectService implements LoggerAwareInterface $mergedQueryParams = array_merge($queryParams, $queryParamsFromRequest); $originalRequest = $originalRequest->withQueryParams($mergedQueryParams); $pageArguments = new PageArguments($site->getRootPageId(), '0', []); + $originalRequest = $originalRequest->withAttribute('routing', $pageArguments); $pageInformation = new PageInformation(); $pageInformation->setId($site->getRootPageId()); $pageInformation->setMountPoint(''); @@ -411,9 +411,7 @@ class RedirectService implements LoggerAwareInterface ); // b/w compat layer $controller->id = $pageInformation->getId(); - $controller->sys_page = GeneralUtility::makeInstance(PageRepository::class); $controller->page = $pageInformation->getPageRecord(); - $controller->MP = $pageInformation->getMountPoint(); $controller->contentPid = $pageInformation->getContentFromPid(); $controller->rootLine = $pageInformation->getRootLine(); $newRequest = $controller->getFromCache($originalRequest); diff --git a/typo3/sysext/seo/Classes/Canonical/CanonicalGenerator.php b/typo3/sysext/seo/Classes/Canonical/CanonicalGenerator.php index 6de1412d3c6d1c6f066dc731da9d4524d323d898..a291d207a09fb26a6a666052341b0c91c3daeb99 100644 --- a/typo3/sysext/seo/Classes/Canonical/CanonicalGenerator.php +++ b/typo3/sysext/seo/Classes/Canonical/CanonicalGenerator.php @@ -18,10 +18,12 @@ declare(strict_types=1); namespace TYPO3\CMS\Seo\Canonical; use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Core\Domain\Page; use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\RootlineUtility; +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\CMS\Frontend\Utility\CanonicalizationUtility; use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent; @@ -31,30 +33,26 @@ use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent; * * @internal this class is not part of TYPO3's Core API. */ -class CanonicalGenerator +readonly class CanonicalGenerator { - protected TypoScriptFrontendController $typoScriptFrontendController; - protected PageRepository $pageRepository; - protected EventDispatcherInterface $eventDispatcher; - - public function __construct(TypoScriptFrontendController $typoScriptFrontendController = null, EventDispatcherInterface $eventDispatcher = null) - { - $this->eventDispatcher = $eventDispatcher ?? GeneralUtility::makeInstance(EventDispatcherInterface::class); - $this->typoScriptFrontendController = $typoScriptFrontendController ?? $this->getTypoScriptFrontendController(); - $this->pageRepository = GeneralUtility::makeInstance(PageRepository::class); - } + public function __construct( + private EventDispatcherInterface $eventDispatcher, + ) {} public function generate(array $params): string { - if ($this->typoScriptFrontendController->config['config']['disableCanonical'] ?? false) { + $typoScriptFrontendController = $this->getTypoScriptFrontendController(); + if ($typoScriptFrontendController->config['config']['disableCanonical'] ?? false) { return ''; } - $event = new ModifyUrlForCanonicalTagEvent('', $params['request'], new Page($params['page'])); + /** @var ServerRequestInterface $request */ + $request = $params['request']; + $event = new ModifyUrlForCanonicalTagEvent($request, new Page($params['page'])); $event = $this->eventDispatcher->dispatch($event); $href = $event->getUrl(); - if (empty($href) && (int)$this->typoScriptFrontendController->page['no_index'] === 1) { + if (empty($href) && (int)$typoScriptFrontendController->page['no_index'] === 1) { return ''; } @@ -68,7 +66,7 @@ class CanonicalGenerator } if (empty($href)) { // 3) Fallback, create canonical URL - $href = $this->checkDefaultCanonical(); + $href = $this->checkDefaultCanonical($request); } if (!empty($href)) { @@ -76,7 +74,7 @@ class CanonicalGenerator 'rel' => 'canonical', 'href' => $href, ], true) . '/>' . LF; - $this->typoScriptFrontendController->additionalHeaderData[] = $canonical; + $typoScriptFrontendController->additionalHeaderData[] = $canonical; return $canonical; } return ''; @@ -84,9 +82,10 @@ class CanonicalGenerator protected function checkForCanonicalLink(): string { - if (!empty($this->typoScriptFrontendController->page['canonical_link'])) { - return $this->typoScriptFrontendController->cObj->createUrl([ - 'parameter' => $this->typoScriptFrontendController->page['canonical_link'], + $typoScriptFrontendController = $this->getTypoScriptFrontendController(); + if (!empty($typoScriptFrontendController->page['canonical_link'])) { + return $typoScriptFrontendController->cObj->createUrl([ + 'parameter' => $typoScriptFrontendController->page['canonical_link'], 'forceAbsoluteUrl' => true, ]); } @@ -95,14 +94,16 @@ class CanonicalGenerator protected function checkContentFromPid(): string { - if ($this->typoScriptFrontendController->contentPid !== $this->typoScriptFrontendController->id) { - $parameter = $this->typoScriptFrontendController->contentPid; + $typoScriptFrontendController = $this->getTypoScriptFrontendController(); + if ($typoScriptFrontendController->contentPid !== $typoScriptFrontendController->id) { + $parameter = $typoScriptFrontendController->contentPid; if ($parameter > 0) { - $targetPage = $this->pageRepository->getPage($parameter, true); + $pageRepository = GeneralUtility::makeInstance(PageRepository::class); + $targetPage = $pageRepository->getPage($parameter, true); if (!empty($targetPage['canonical_link'])) { $parameter = $targetPage['canonical_link']; } - return $this->typoScriptFrontendController->cObj->createUrl([ + return $typoScriptFrontendController->cObj->createUrl([ 'parameter' => $parameter, 'forceAbsoluteUrl' => true, ]); @@ -111,10 +112,11 @@ class CanonicalGenerator return ''; } - protected function checkDefaultCanonical(): string + protected function checkDefaultCanonical(ServerRequestInterface $request): string { + $typoScriptFrontendController = $this->getTypoScriptFrontendController(); // We should only create a canonical link to the target, if the target is within a valid site root - $inSiteRoot = $this->isPageWithinSiteRoot($this->typoScriptFrontendController->id); + $inSiteRoot = $this->isPageWithinSiteRoot($typoScriptFrontendController->id); if (!$inSiteRoot) { return ''; } @@ -122,24 +124,26 @@ class CanonicalGenerator // Temporarily remove current mountpoint information as we want to have the // URL of the target page and not of the page within the mountpoint if the // current page is a mountpoint. - $previousMp = $this->typoScriptFrontendController->MP; - $this->typoScriptFrontendController->MP = ''; - - $link = $this->typoScriptFrontendController->cObj->createUrl([ - 'parameter' => $this->typoScriptFrontendController->id . ',' . $this->typoScriptFrontendController->getPageArguments()->getPageType(), + $pageInformation = clone $request->getAttribute('frontend.page.information'); + $pageInformation->setMountPoint(''); + $request = $request->withAttribute('frontend.page.information', $pageInformation); + $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class, $typoScriptFrontendController); + $cObj->setRequest($request); + $cObj->start($pageInformation->getPageRecord(), 'pages'); + $link = $cObj->createUrl([ + 'parameter' => $typoScriptFrontendController->id . ',' . $request->getAttribute('routing')->getPageType(), 'forceAbsoluteUrl' => true, 'addQueryString' => true, 'addQueryString.' => [ 'exclude' => implode( ',', CanonicalizationUtility::getParamsToExcludeForCanonicalizedUrl( - $this->typoScriptFrontendController->id, + $typoScriptFrontendController->id, (array)$GLOBALS['TYPO3_CONF_VARS']['FE']['additionalCanonicalizedUrlParameters'] ) ), ], ]); - $this->typoScriptFrontendController->MP = $previousMp; return $link; } diff --git a/typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php b/typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php index 69b20ff60280cc0aaf5c7361da1adc6cf38abe69..0227192cadd79240f91c17ca5872d6c03154e18a 100644 --- a/typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php +++ b/typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php @@ -25,8 +25,9 @@ use TYPO3\CMS\Core\Domain\Page; */ final class ModifyUrlForCanonicalTagEvent { + private string $url = ''; + public function __construct( - private string $url, private readonly ServerRequestInterface $request, private readonly Page $page ) {} diff --git a/typo3/sysext/seo/Classes/XmlSitemap/XmlSitemapRenderer.php b/typo3/sysext/seo/Classes/XmlSitemap/XmlSitemapRenderer.php index 9957496dc01e624970d846d037ee79decad36489..d005b7b101175778437cc3fb8dc0867daf0db35d 100644 --- a/typo3/sysext/seo/Classes/XmlSitemap/XmlSitemapRenderer.php +++ b/typo3/sysext/seo/Classes/XmlSitemap/XmlSitemapRenderer.php @@ -57,7 +57,7 @@ final class XmlSitemapRenderer $templatePaths->setFormat('xml'); $sitemapType = $typoScriptConfiguration['sitemapType'] ?? 'xmlSitemap'; $view = GeneralUtility::makeInstance(TemplateView::class, $renderingContext); - $view->assign('type', $request->getAttribute('frontend.controller')->getPageArguments()->getPageType()); + $view->assign('type', $request->getAttribute('routing')->getPageType()); $view->assign('sitemapType', $sitemapType); $configConfiguration = $configurationArrayWithoutDots['config'] ?? []; if (!empty($sitemapName = ($request->getQueryParams()['sitemap'] ?? null))) { diff --git a/typo3/sysext/seo/Configuration/Services.yaml b/typo3/sysext/seo/Configuration/Services.yaml index 04e09af63e7504cd25fc9c7bffe84f4617bba039..38f95453bf818ebfd80f94a63b15839481391402 100644 --- a/typo3/sysext/seo/Configuration/Services.yaml +++ b/typo3/sysext/seo/Configuration/Services.yaml @@ -10,6 +10,9 @@ services: TYPO3\CMS\Seo\MetaTag\MetaTagGenerator: public: true + TYPO3\CMS\Seo\Canonical\CanonicalGenerator: + public: true + TYPO3\CMS\Seo\XmlSitemap\XmlSitemapRenderer: public: true diff --git a/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php b/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php index ff4d35508441ef7e36b73c056183f58970454af5..ef84aa387663fbb52b6620075297c4a1eab90510 100644 --- a/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php +++ b/typo3/sysext/seo/Tests/Functional/Canonical/CanonicalGeneratorTest.php @@ -175,7 +175,7 @@ final class CanonicalGeneratorTest extends FunctionalTestCase $GLOBALS['TSFE']->id = 123; $GLOBALS['TSFE']->page['no_index'] = 1; - (new CanonicalGenerator())->generate(['request' => new ServerRequest('https://example.com'), 'page' => ['uid' => 123]]); + $this->get(CanonicalGenerator::class)->generate(['request' => new ServerRequest('https://example.com'), 'page' => ['uid' => 123]]); self::assertInstanceOf(ModifyUrlForCanonicalTagEvent::class, $modifyUrlForCanonicalTagEvent); self::assertEmpty('', $modifyUrlForCanonicalTagEvent->getUrl()); diff --git a/typo3/sysext/seo/Tests/Unit/Event/ModifyUrlForCanonicalTagEventTest.php b/typo3/sysext/seo/Tests/Unit/Event/ModifyUrlForCanonicalTagEventTest.php index 0607b423feaa9149310cc91fa5859eeab3263881..8abe06c2e375a670230d7000a3c27622184815f9 100644 --- a/typo3/sysext/seo/Tests/Unit/Event/ModifyUrlForCanonicalTagEventTest.php +++ b/typo3/sysext/seo/Tests/Unit/Event/ModifyUrlForCanonicalTagEventTest.php @@ -19,7 +19,6 @@ namespace TYPO3\CMS\Seo\Tests\Unit\Event; use TYPO3\CMS\Core\Domain\Page; use TYPO3\CMS\Core\Http\ServerRequest; -use TYPO3\CMS\Core\Http\Uri; use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; @@ -30,12 +29,12 @@ final class ModifyUrlForCanonicalTagEventTest extends UnitTestCase */ public function gettersReturnInitializedObjects(): void { - $url = (string)new Uri('https://example.com'); - $request = (new ServerRequest($url)); + $request = (new ServerRequest('')); $page = new Page(['uid' => 123]); - $event = new ModifyUrlForCanonicalTagEvent($url, $request, $page); + $event = new ModifyUrlForCanonicalTagEvent($request, $page); + $event->setUrl('https://example.com'); - self::assertEquals($url, $event->getUrl()); + self::assertEquals('https://example.com', $event->getUrl()); self::assertEquals($request, $event->getRequest()); self::assertEquals($page, $event->getPage()); }