[TASK] Move rootPage resolving into PSR-15 middleware 64/56664/2
authorBenni Mack <benni@typo3.org>
Sun, 15 Apr 2018 07:38:15 +0000 (09:38 +0200)
committerBenni Mack <benni@typo3.org>
Sun, 15 Apr 2018 10:17:17 +0000 (12:17 +0200)
The functionality to resolve the "domain start page" - the page ID
where a sys_domain record is found, is moved from TSFE/sys_page
into the SiteResolver middleware, making the domain start page value
available at an earlier point of a request.

Change of behaviours:
- TSFE->domainStartPage is now filled earlier than before
- TSFE->domainStartPage is now filled regardless of access checks of the
permissions of that page record, as the check is done later-on again anyways.

For the sake of completeness:
If a site is configured, this code is not executed anymore, as the site contains
the rootpage ID already anyways.

The method "TypoScriptFrontendController->findDomainRecord"
is removed, as it was marked as private and should have not been
used outside TYPO3 Core.

The method "PageRepository->getDomainStartPage" is marked
as deprecated as it is not called anymore.

Resolves: #84725
Releases: master
Change-Id: I5c420701eb463630d6286578ff582cb0e4e1dd35
Reviewed-on: https://review.typo3.org/56664
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Frans Saris <franssaris@gmail.com>
Tested-by: Frans Saris <franssaris@gmail.com>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/core/Documentation/Changelog/master/Deprecation-84725-SysDomainResolvingMovedIntoMiddleware.rst [new file with mode: 0644]
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
typo3/sysext/frontend/Classes/Middleware/SiteResolver.php
typo3/sysext/frontend/Classes/Page/PageRepository.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84725-SysDomainResolvingMovedIntoMiddleware.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84725-SysDomainResolvingMovedIntoMiddleware.rst
new file mode 100644 (file)
index 0000000..669361b
--- /dev/null
@@ -0,0 +1,46 @@
+.. include:: ../../Includes.txt
+
+================================================================
+Deprecation: #84725 - sys_domain resolving moved into middleware
+================================================================
+
+See :issue:`84725`
+
+Description
+===========
+
+The PHP method `PageRepository->getDomainStartPage()` has been marked as deprecated.
+
+The PHP method `TypoScriptFrontendController->findDomainRecord()` which was marked
+as internal, has been removed.
+
+As both methods have been used to resolve the root page ID of the current request,
+they were solely there to fill :php:`$GLOBALS['TSFE']->domainStartPage` which is now filled
+at an earlier stage through the :php:`SiteResolver` middleware.
+
+
+Impact
+======
+
+Calling the PageRepository method will trigger a deprecation warning.
+
+Calling the TypoScriptFrontendController method will result in a fatal PHP error.
+
+
+Affected Installations
+======================
+
+TYPO3 installations with third-party extensions calling the methods directly, usually
+related to resolve a page ID or to mimic a frontend call.
+
+
+Migration
+=========
+
+If the return value is needed, access :php:`$GLOBALS['TSFE']->domainStartPage` directly.
+
+If the functionality is used in a third-party functionality and still needed,
+ensure to extend from `SiteResolver` middleware to call the now-protected method equivalents
+instead.
+
+.. index:: Frontend, PHP-API, FullyScanned, ext:frontend
\ No newline at end of file
index 73e6f56..5f15c87 100644 (file)
@@ -1276,12 +1276,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         $timeTracker->pull();
         // We find the first page belonging to the current domain
         $timeTracker->push('fetch_the_id domain/', '');
-        // The page_id of the current domain
-        if ($this->getCurrentSiteLanguage()) {
-            $this->domainStartPage = $this->getCurrentSiteLanguage()->getSite()->getRootPageId();
-        } else {
-            $this->domainStartPage = $this->findDomainRecord($GLOBALS['TYPO3_CONF_VARS']['SYS']['recursiveDomainSearch']);
-        }
         if (!$this->id) {
             if ($this->domainStartPage) {
                 // If the id was not previously set, set it to the id of the domain.
@@ -1838,30 +1832,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface
     }
 
     /**
-     * Looking up a domain record based on HTTP_HOST
-     *
-     * @param bool $recursive If set, it looks "recursively" meaning that a domain like "123.456.typo3.com" would find a domain record like "typo3.com" if "123.456.typo3.com" or "456.typo3.com" did not exist.
-     * @return int Returns the page id of the page where the domain record was found.
-     * @access private
-     */
-    public function findDomainRecord($recursive = false)
-    {
-        if ($recursive) {
-            $pageUid = 0;
-            $host = explode('.', GeneralUtility::getIndpEnv('HTTP_HOST'));
-            while (count($host)) {
-                $pageUid = $this->sys_page->getDomainStartPage(implode('.', $host), GeneralUtility::getIndpEnv('SCRIPT_NAME'));
-                if ($pageUid) {
-                    return $pageUid;
-                }
-                array_shift($host);
-            }
-            return $pageUid;
-        }
-        return $this->sys_page->getDomainStartPage(GeneralUtility::getIndpEnv('HTTP_HOST'), GeneralUtility::getIndpEnv('SCRIPT_NAME'));
-    }
-
-    /**
      * Page unavailable handler for use in frontend plugins from extensions.
      *
      * @param string $reason Reason text
index fec8cc2..0fb79a4 100644 (file)
@@ -19,19 +19,22 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
+use TYPO3\CMS\Core\Http\NormalizedParams;
 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;
 
 /**
- * Identify the current request and resolve the site to it.
- * After that middleware, TSFE should be populated with
- * - language configuration
- * - site configuration
+ * Identifies if a site is configured for the request, based on "id" and "L" GET/POST parameters, or the requested
+ * string.
  *
- * Properties like config.sys_language_uid and config.language is then set for TypoScript.
+ * If a site is found, the request is populated with the found language+site objects. If none is found, the main magic
+ * is handled by the PageResolver middleware.
+ *
+ * In addition to that, TSFE gets the $domainStartPage information resolved and added.
  */
 class SiteResolver implements MiddlewareInterface
 {
@@ -83,6 +86,85 @@ class SiteResolver implements MiddlewareInterface
             // for bw-compat we update $GLOBALS[TYPO3_REQUEST] to be used later in TSFE.
             $GLOBALS['TYPO3_REQUEST'] = $request;
         }
+
+        // Now resolve the root page of the site, the page_id of the current domain
+        if ($site instanceof Site) {
+            $GLOBALS['TSFE']->domainStartPage = $site->getRootPageId();
+        } else {
+            $GLOBALS['TSFE']->domainStartPage = $this->findDomainRecord($request->getAttribute('normalizedParams'), (bool)$GLOBALS['TYPO3_CONF_VARS']['SYS']['recursiveDomainSearch']);
+        }
+
         return $handler->handle($request);
     }
+
+    /**
+     * Looking up a domain record based on server parameters HTTP_HOST
+     *
+     * @param NormalizedParams $requestParams used to get sanitized information of the current request
+     * @param bool $recursive If set, it looks "recursively" meaning that a domain like "123.456.typo3.com" would find a domain record like "typo3.com" if "123.456.typo3.com" or "456.typo3.com" did not exist.
+     * @return int|null Returns the page id of the page where the domain record was found or null if no sys_domain record found.
+     * previously found at \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::findDomainRecord()
+     */
+    protected function findDomainRecord(NormalizedParams $requestParams, $recursive = false): ?int
+    {
+        if ($recursive) {
+            $pageUid = 0;
+            $host = explode('.', $requestParams->getHttpHost());
+            while (count($host)) {
+                $pageUid = $this->getRootPageIdFromDomainRecord(implode('.', $host), $requestParams->getScriptName());
+                if ($pageUid) {
+                    return $pageUid;
+                }
+                array_shift($host);
+            }
+            return $pageUid;
+        }
+        return $this->getRootPageIdFromDomainRecord($requestParams->getHttpHost(), $requestParams->getScriptName());
+    }
+
+    /**
+     * Will find the page ID carrying the domain record matching the input domain.
+     *
+     * @param string $domain Domain name to search for. Eg. "www.typo3.com". Typical the HTTP_HOST value.
+     * @param string $path Path for the current script in domain. Eg. "/somedir/subdir". Typ. supplied by \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('SCRIPT_NAME')
+     * @return int|null If found, returns integer with page UID where found. Otherwise null.
+     * previously found at PageRepository::getDomainStartPage
+     */
+    protected function getRootPageIdFromDomainRecord(string $domain, string $path = ''): ?int
+    {
+        list($domain) = explode(':', $domain);
+        $domain = strtolower(preg_replace('/\\.$/', '', $domain));
+        // Removing extra trailing slashes
+        $path = trim(preg_replace('/\\/[^\\/]*$/', '', $path));
+        // Appending to domain string
+        $domain .= $path;
+        $domain = preg_replace('/\\/*$/', '', $domain);
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_domain');
+        $queryBuilder->getRestrictions()->removeAll();
+        $row = $queryBuilder
+            ->select(
+                'pid'
+            )
+            ->from('sys_domain')
+            ->where(
+                $queryBuilder->expr()->eq(
+                    'hidden',
+                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
+                ),
+                $queryBuilder->expr()->orX(
+                    $queryBuilder->expr()->eq(
+                        'domainName',
+                        $queryBuilder->createNamedParameter($domain, \PDO::PARAM_STR)
+                    ),
+                    $queryBuilder->expr()->eq(
+                        'domainName',
+                        $queryBuilder->createNamedParameter($domain . '/', \PDO::PARAM_STR)
+                    )
+                )
+            )
+            ->setMaxResults(1)
+            ->execute()
+            ->fetch();
+        return $row ? (int)$row['pid'] : null;
+    }
 }
index 9cd08fd..1b98f69 100644 (file)
@@ -877,6 +877,7 @@ class PageRepository implements LoggerAwareInterface
         }
         return $page;
     }
+
     /**
      * Will find the page carrying the domain record matching the input domain.
      *
@@ -885,9 +886,11 @@ class PageRepository implements LoggerAwareInterface
      * @param string $request_uri Request URI: Used to get parameters from if they should be appended. Typ. supplied by \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI')
      * @return mixed If found, returns integer with page UID where found. Otherwise blank. Might exit if location-header is sent, see description.
      * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::findDomainRecord()
+     * @deprecated will be removed in TYPO3 v10.0.
      */
     public function getDomainStartPage($domain, $path = '', $request_uri = '')
     {
+        trigger_error('This method will be removed in TYPO3 v10.0. As the SiteResolver middleware resolves the domain start page.', E_USER_DEPRECATED);
         $domain = explode(':', $domain);
         $domain = strtolower(preg_replace('/\\.$/', '', $domain[0]));
         // Removing extra trailing slashes
index 4808ea5..95eb70c 100644 (file)
@@ -2116,4 +2116,18 @@ return [
             'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
         ],
     ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->findDomainRecord' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 1,
+        'restFiles' => [
+            'Deprecation-84725-SysDomainResolvingMovedIntoMiddleware.rst',
+        ],
+    ],
+    'TYPO3\CMS\Frontend\Page\PageRepository->getDomainStartPage' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 3,
+        'restFiles' => [
+            'Deprecation-84725-SysDomainResolvingMovedIntoMiddleware.rst',
+        ],
+    ],
 ];