use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\UserAspect;
use TYPO3\CMS\Core\Context\WorkspaceAspect;
-use TYPO3\CMS\Core\Http\RedirectResponse;
-use TYPO3\CMS\Core\Routing\PageRouter;
-use TYPO3\CMS\Core\Routing\RouteResult;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Database\Query\Restriction\FrontendWorkspaceRestriction;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\Routing\RouteNotFoundException;
+use TYPO3\CMS\Core\Routing\SiteRouteResult;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\Entity\SiteInterface;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Type\Bitmask\Permission;
use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Frontend\Controller\ErrorController;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
// Resolve the page ID based on TYPO3's native routing functionality
if ($hasSiteConfiguration) {
- /** @var RouteResult $previousResult */
- $previousResult = $request->getAttribute('routing', new RouteResult($request->getUri(), $site, $language));
- if (!empty($previousResult->getTail())) {
+ /** @var SiteRouteResult $previousResult */
+ $previousResult = $request->getAttribute('routing', null);
+ if (!$previousResult) {
+ return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $request,
+ 'The requested page does not exist',
+ ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
+ );
+ }
+
+ $requestId = (string)($request->getQueryParams()['id'] ?? '');
+ if (!empty($requestId) && !empty($page = $this->resolvePageId($requestId))) {
+ // Legacy URIs (?id=12345) takes precedence, not matter if a route is given
+ $pageArguments = new PageArguments(
+ (int)($page['l10n_parent'] ?: $page['uid']),
+ (string)($request->getQueryParams()['type'] ?? '0'),
+ [],
+ [],
+ $request->getQueryParams()
+ );
+ } else {
// Check for the route
- $routeResult = $this->getPageRouter()->matchRoute($request, $previousResult->getTail(), $site, $language);
- $request = $request->withAttribute('routing', $routeResult);
- if (is_array($routeResult['page'])) {
- $page = $routeResult['page'];
- $this->controller->id = (int)($page['l10n_parent'] > 0 ? $page['l10n_parent'] : $page['uid']);
- $tail = $routeResult->getTail();
- $requestedUri = $request->getUri();
- // the request was called with "/my-page" but it's actually called "/my-page/", let's do a redirect
- if ($tail === '' && substr($requestedUri->getPath(), -1) !== substr($page['slug'], -1)) {
- $uri = $requestedUri->withPath($requestedUri->getPath() . '/');
- return new RedirectResponse($uri, 307);
- }
- if ($tail === '/') {
- $uri = $requestedUri->withPath(rtrim($requestedUri->getPath(), '/'));
- return new RedirectResponse($uri, 307);
- }
- if (!empty($tail)) {
- // @todo: kick in the resolvers for the RouteEnhancers at this point
- return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
- $request,
- 'The requested page does not exist',
- ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
- );
- }
- } else {
+ try {
+ $pageArguments = $site->getRouter()->matchRequest($request, $previousResult);
+ } catch (RouteNotFoundException $e) {
return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
$request,
'The requested page does not exist',
['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
);
}
- // At this point, we later get further route modifiers
- // for bw-compat we update $GLOBALS[TYPO3_REQUEST] to be used later in TSFE.
- $GLOBALS['TYPO3_REQUEST'] = $request;
}
+ if (!$pageArguments->getPageId()) {
+ return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $request,
+ 'The requested page does not exist',
+ ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
+ );
+ }
+
+ $this->controller->id = $pageArguments->getPageId();
+ $this->controller->type = $pageArguments->getPageType() ?? $this->controller->type;
+ $request = $request->withAttribute('routing', $pageArguments);
+ // stop in case arguments are dirty (=defined twice in route and GET query parameters)
+ if ($pageArguments->areDirty()) {
+ return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $request,
+ 'The requested URL is not distinct',
+ ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
+ );
+ }
+
+ // merge the PageArguments with the request query parameters
+ $queryParams = array_replace_recursive($request->getQueryParams(), $pageArguments->getArguments());
+ $request = $request->withQueryParams($queryParams);
+ $this->controller->setPageArguments($pageArguments);
+
+ // At this point, we later get further route modifiers
+ // for bw-compat we update $GLOBALS[TYPO3_REQUEST] to be used later in TSFE.
+ $GLOBALS['TYPO3_REQUEST'] = $request;
} else {
// old-school page resolving for realurl, cooluri etc.
$this->controller->siteScript = $request->getAttribute('normalizedParams')->getSiteScript();
- $this->checkAlternativeIdMethods($this->controller);
}
$this->controller->determineId();
unset($GLOBALS['BE_USER']);
// Register an empty backend user as aspect
$this->setBackendUserAspect(GeneralUtility::makeInstance(Context::class), null);
- if (!$hasSiteConfiguration) {
- $this->checkAlternativeIdMethods($this->controller);
- }
$this->controller->determineId();
}
- // Evaluate the cache hash parameter
- $this->controller->makeCacheHash();
-
return $handler->handle($request);
}
/**
- * @return PageRouter
+ * @param string $pageId
+ * @return array|null
*/
- protected function getPageRouter(): PageRouter
+ protected function resolvePageId(string $pageId): ?array
{
- return GeneralUtility::makeInstance(PageRouter::class);
- }
+ $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+ ->getQueryBuilderForTable('pages');
+ $queryBuilder
+ ->getRestrictions()
+ ->removeAll()
+ ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
+ ->add(GeneralUtility::makeInstance(FrontendWorkspaceRestriction::class));
- /**
- * Provides ways to bypass the '?id=[xxx]&type=[xx]' format, using either PATH_INFO or Server Rewrites
- *
- * Two options:
- * 1) Use PATH_INFO (also Apache) to extract id and type from that var. Does not require any special modules compiled with apache. (less typical)
- * 2) Using hook which enables features like those provided from "realurl" extension (AKA "Speaking URLs")
- *
- * @param TypoScriptFrontendController $tsfe
- */
- protected function checkAlternativeIdMethods(TypoScriptFrontendController $tsfe)
- {
- // Call post processing function for custom URL methods.
- $_params = ['pObj' => &$tsfe];
- foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'] ?? [] as $_funcRef) {
- GeneralUtility::callUserFunction($_funcRef, $_params, $tsfe);
+ if (MathUtility::canBeInterpretedAsInteger($pageId)) {
+ $constraint = $queryBuilder->expr()->eq(
+ 'uid',
+ $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
+ );
+ } else {
+ $constraint = $queryBuilder->expr()->eq(
+ 'alias',
+ $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_STR)
+ );
+ }
+
+ $statement = $queryBuilder
+ ->select('uid', 'l10n_parent', 'pid')
+ ->from('pages')
+ ->where($constraint)
+ ->execute();
+
+ $page = $statement->fetch();
+ if (empty($page)) {
+ return null;
}
+ return $page;
}
/**