[TASK] Use RootlineUtility directly 90/57590/8
authorBenni Mack <benni@typo3.org>
Fri, 13 Jul 2018 18:53:44 +0000 (20:53 +0200)
committerBenni Mack <benni@typo3.org>
Tue, 24 Jul 2018 05:42:35 +0000 (07:42 +0200)
Instead of calling PageRepository to fetch the rootline, RootlineUtility
can do that now directly.

However, all exceptions are more specific and caught specifically, for
each use-case.

Additionally, PageRepository->getRootline() is deprecated now. For this
reason, the deprecation for the argument $ignoreMPerrors is removed
again, as it does not make sense anymore.

Resolves: #85557
Releases: master
Change-Id: I5a9192311c5616f5a58e89a39c3869b593e97968
Reviewed-on: https://review.typo3.org/57590
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
22 files changed:
typo3/sysext/backend/Classes/Controller/Page/TreeController.php
typo3/sysext/core/Classes/Exception/Page/BrokenRootLineException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Exception/Page/CircularRootLineException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Exception/Page/MountPointException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Exception/Page/MountPointsDisabledException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Exception/Page/PageNotFoundException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Exception/Page/PagePropertyRelationNotFoundException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Exception/Page/RootLineException.php [new file with mode: 0644]
typo3/sysext/core/Classes/Utility/RootlineUtility.php
typo3/sysext/core/Documentation/Changelog/9.3/Deprecation-85105-3rdMethodArgumentInPageRepository-getRootLine.rst [deleted file]
typo3/sysext/core/Documentation/Changelog/master/Deprecation-85557-PageRepository-getRootLine.rst [new file with mode: 0644]
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
typo3/sysext/frontend/Classes/Page/PageRepository.php
typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
typo3/sysext/frontend/Tests/Functional/ContentObject/ContentObjectRendererTest.php
typo3/sysext/indexed_search/Classes/Controller/SearchController.php
typo3/sysext/indexed_search/Classes/Hook/CrawlerHook.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodArgumentDroppedMatcher.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
typo3/sysext/workspaces/Tests/Functional/DataHandling/IRRE/CSV/Modify/ActionTest.php
typo3/sysext/workspaces/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/ActionTest.php
typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Modify/ActionTest.php

index 7ddda5d..0892c64 100644 (file)
@@ -22,6 +22,7 @@ use TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Exception\Page\RootLineException;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -29,7 +30,7 @@ use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Page\PageRepository;
+use TYPO3\CMS\Core\Utility\RootlineUtility;
 use TYPO3\CMS\Workspaces\Service\WorkspaceService;
 
 /**
@@ -327,7 +328,6 @@ class TreeController
     {
         $backendUser = $this->getBackendUser();
         $repository = GeneralUtility::makeInstance(PageTreeRepository::class, (int)$backendUser->workspace);
-        $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
 
         $entryPoints = (int)($backendUser->uc['pageTree_temporaryMountPoint'] ?? 0);
         if ($entryPoints > 0) {
@@ -353,7 +353,11 @@ class TreeController
             }
 
             if (!empty($this->backgroundColors) && is_array($this->backgroundColors)) {
-                $entryPointRootLine = $pageRepository->getRootLine($entryPoint);
+                try {
+                    $entryPointRootLine = GeneralUtility::makeInstance(RootlineUtility::class, $entryPoint)->get();
+                } catch (RootLineException $e) {
+                    $entryPointRootLine = [];
+                }
                 foreach ($entryPointRootLine as $rootLineEntry) {
                     $parentUid = $rootLineEntry['uid'];
                     if (!empty($this->backgroundColors[$parentUid]) && empty($this->backgroundColors[$entryPoint])) {
diff --git a/typo3/sysext/core/Classes/Exception/Page/BrokenRootLineException.php b/typo3/sysext/core/Classes/Exception/Page/BrokenRootLineException.php
new file mode 100644 (file)
index 0000000..260a3ce
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Exception for root line traversal when a page within the root line traversal is missing / can not be resolved
+ */
+class BrokenRootLineException extends RootLineException
+{
+}
diff --git a/typo3/sysext/core/Classes/Exception/Page/CircularRootLineException.php b/typo3/sysext/core/Classes/Exception/Page/CircularRootLineException.php
new file mode 100644 (file)
index 0000000..afdc546
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Exception for root line traversal when a loop is detected
+ */
+class CircularRootLineException extends RootLineException
+{
+}
diff --git a/typo3/sysext/core/Classes/Exception/Page/MountPointException.php b/typo3/sysext/core/Classes/Exception/Page/MountPointException.php
new file mode 100644 (file)
index 0000000..7913d99
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Exception thrown if a mount point is used
+ */
+class MountPointException extends RootLineException
+{
+}
diff --git a/typo3/sysext/core/Classes/Exception/Page/MountPointsDisabledException.php b/typo3/sysext/core/Classes/Exception/Page/MountPointsDisabledException.php
new file mode 100644 (file)
index 0000000..3faad95
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Exception thrown if a mount point is used but disabled via
+ * "$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']"
+ */
+class MountPointsDisabledException extends MountPointException
+{
+}
diff --git a/typo3/sysext/core/Classes/Exception/Page/PageNotFoundException.php b/typo3/sysext/core/Classes/Exception/Page/PageNotFoundException.php
new file mode 100644 (file)
index 0000000..9219431
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Exception thrown if a page can not be fetched from the DB
+ */
+class PageNotFoundException extends RootLineException
+{
+}
diff --git a/typo3/sysext/core/Classes/Exception/Page/PagePropertyRelationNotFoundException.php b/typo3/sysext/core/Classes/Exception/Page/PagePropertyRelationNotFoundException.php
new file mode 100644 (file)
index 0000000..53578a0
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Exception thrown if a page property relation can not be fetched from the DB
+ */
+class PagePropertyRelationNotFoundException extends \RuntimeException
+{
+}
diff --git a/typo3/sysext/core/Classes/Exception/Page/RootLineException.php b/typo3/sysext/core/Classes/Exception/Page/RootLineException.php
new file mode 100644 (file)
index 0000000..512b36b
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Exception\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Base exception for root line traversal. This extends from RuntimeException for historical reasons
+ * and bw compatibility
+ */
+class RootLineException extends \RuntimeException
+{
+}
index bf5d704..b941273 100644 (file)
@@ -19,6 +19,11 @@ use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
+use TYPO3\CMS\Core\Exception\Page\BrokenRootLineException;
+use TYPO3\CMS\Core\Exception\Page\CircularRootLineException;
+use TYPO3\CMS\Core\Exception\Page\MountPointsDisabledException;
+use TYPO3\CMS\Core\Exception\Page\PageNotFoundException;
+use TYPO3\CMS\Core\Exception\Page\PagePropertyRelationNotFoundException;
 use TYPO3\CMS\Frontend\Page\PageRepository;
 
 /**
@@ -120,7 +125,7 @@ class RootlineUtility
      * @param int $uid
      * @param string $mountPointParameter
      * @param PageRepository|Context $context - @deprecated PageRepository is used until TYPO3 v9.4, but now the third parameter should be a Context object
-     * @throws \RuntimeException
+     * @throws MountPointsDisabledException
      */
     public function __construct($uid, $mountPointParameter = '', $context = null)
     {
@@ -142,7 +147,7 @@ class RootlineUtility
         $this->workspaceUid = $this->context->getPropertyFromAspect('workspace', 'id', 0);
         if ($this->mountPointParameter !== '') {
             if (!$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
-                throw new \RuntimeException('Mount-Point Pages are disabled for this installation. Cannot resolve a Rootline for a page with Mount-Points', 1343462896);
+                throw new MountPointsDisabledException('Mount-Point Pages are disabled for this installation. Cannot resolve a Rootline for a page with Mount-Points', 1343462896);
             }
             $this->parseMountPointParameter();
         }
@@ -225,7 +230,7 @@ class RootlineUtility
      * Queries the database for the page record and returns it.
      *
      * @param int $uid Page id
-     * @throws \RuntimeException
+     * @throws PageNotFoundException
      * @return array
      */
     protected function getRecordArray($uid)
@@ -246,7 +251,7 @@ class RootlineUtility
                 ->execute()
                 ->fetch();
             if (empty($row)) {
-                throw new \RuntimeException('Could not fetch page data for uid ' . $uid . '.', 1343589451);
+                throw new PageNotFoundException('Could not fetch page data for uid ' . $uid . '.', 1343589451);
             }
             $this->pageContext->versionOL('pages', $row, false, true);
             $this->pageContext->fixVersioningPid('pages', $row);
@@ -259,7 +264,7 @@ class RootlineUtility
             }
         }
         if (!is_array(self::$pageRecordCache[$currentCacheIdentifier])) {
-            throw new \RuntimeException('Broken rootline. Could not resolve page with uid ' . $uid . '.', 1343464101);
+            throw new PageNotFoundException('Broken rootline. Could not resolve page with uid ' . $uid . '.', 1343464101);
         }
         return self::$pageRecordCache[$currentCacheIdentifier];
     }
@@ -269,7 +274,7 @@ class RootlineUtility
      *
      * @param int $uid page ID
      * @param array $pageRecord Page record (possibly overlaid) to be extended with relations
-     * @throws \RuntimeException
+     * @throws PagePropertyRelationNotFoundException
      * @return array $pageRecord with additional relations
      */
     protected function enrichWithRelationFields($uid, array $pageRecord)
@@ -341,7 +346,7 @@ class RootlineUtility
                     try {
                         $statement = $queryBuilder->execute();
                     } catch (DBALException $e) {
-                        throw new \RuntimeException('Could to resolve related records for page ' . $uid . ' and foreign_table ' . htmlspecialchars($table), 1343589452);
+                        throw new PagePropertyRelationNotFoundException('Could to resolve related records for page ' . $uid . ' and foreign_table ' . htmlspecialchars($table), 1343589452);
                     }
                     $relatedUids = [];
                     while ($row = $statement->fetch()) {
@@ -376,7 +381,7 @@ class RootlineUtility
     /**
      * Actual function to generate the rootline and cache it
      *
-     * @throws \RuntimeException
+     * @throws CircularRootLineException
      */
     protected function generateRootlineCache()
     {
@@ -400,7 +405,7 @@ class RootlineUtility
             foreach ($rootline as $entry) {
                 $cacheTags[] = 'pageId_' . $entry['uid'];
                 if ($entry['uid'] == $this->pageUid) {
-                    throw new \RuntimeException('Circular connection in rootline for page with uid ' . $this->pageUid . ' found. Check your mountpoint configuration.', 1343464103);
+                    throw new CircularRootLineException('Circular connection in rootline for page with uid ' . $this->pageUid . ' found. Check your mountpoint configuration.', 1343464103);
                 }
             }
         } else {
@@ -428,7 +433,7 @@ class RootlineUtility
      *
      * @param array $mountedPageData page record array of mounted page
      * @param array $mountPointPageData page record array of mount point page
-     * @throws \RuntimeException
+     * @throws BrokenRootLineException
      * @return array
      */
     protected function processMountedPage(array $mountedPageData, array $mountPointPageData)
@@ -436,7 +441,7 @@ class RootlineUtility
         $mountPid = $mountPointPageData['mount_pid'] ?? null;
         $uid = $mountedPageData['uid'] ?? null;
         if ($mountPid != $uid) {
-            throw new \RuntimeException('Broken rootline. Mountpoint parameter does not match the actual rootline. mount_pid (' . $mountPid . ') does not match page uid (' . $uid . ').', 1343464100);
+            throw new BrokenRootLineException('Broken rootline. Mountpoint parameter does not match the actual rootline. mount_pid (' . $mountPid . ') does not match page uid (' . $uid . ').', 1343464100);
         }
         // Current page replaces the original mount-page
         $mountUid = $mountPointPageData['uid'] ?? null;
diff --git a/typo3/sysext/core/Documentation/Changelog/9.3/Deprecation-85105-3rdMethodArgumentInPageRepository-getRootLine.rst b/typo3/sysext/core/Documentation/Changelog/9.3/Deprecation-85105-3rdMethodArgumentInPageRepository-getRootLine.rst
deleted file mode 100644 (file)
index 4945035..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-.. include:: ../../Includes.txt
-
-==========================================================================
-Deprecation: #85105 - 3rd method argument in PageRepository->getRootLine()
-==========================================================================
-
-See :issue:`85105`
-
-Description
-===========
-
-The third argument of :php:`TYPO3\CMS\Frontend\Page\PageRepository->getRootLine()` has been marked
-as deprecated.
-
-That argument was mainly used to catch exceptions when a faulty rootline is found. The PageRepository
-currently handles the exceptions in a special way with some special magic. However, it is more
-feasible to always throw an exception and have the caller handle possible exceptions.
-
-
-Impact
-======
-
-Calling the method with three arguments will trigger a PHP :php:`E_USER_DEPRECATED` error.
-
-
-Affected Installations
-======================
-
-TYPO3 installations with extensions calling the method directly with the 3rd argument.
-
-
-Migration
-=========
-
-Remove the third argument from code in PHP and wrap a try/catch block around the method call.
-
-.. index:: Frontend, PHP-API, FullyScanned
\ No newline at end of file
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-85557-PageRepository-getRootLine.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-85557-PageRepository-getRootLine.rst
new file mode 100644 (file)
index 0000000..2495143
--- /dev/null
@@ -0,0 +1,34 @@
+.. include:: ../../Includes.txt
+
+=================================================
+Deprecation: #85557 - PageRepository->getRootLine
+=================================================
+
+See :issue:`85557`
+
+Description
+===========
+
+The public method :php:`TYPO3\CMS\Frontend\Page\PageRepository->getRootLine` has been marked as
+deprecated.
+
+
+Impact
+======
+
+Calling the method directly will trigger a deprecation message.
+
+
+Affected Installations
+======================
+
+TYPO3 installations with custom extensions calling this method directly.
+
+
+Migration
+=========
+
+As `getRootLine()` acts as a simple wrapper around `RootlineUtility`, it is recommended to instantiate
+the RootLineUtility directly and catch any specific exceptions directly.
+
+.. index:: Frontend, PHP-API, FullyScanned, ext:frontend
\ No newline at end of file
index 30340ca..0bb14d0 100644 (file)
@@ -41,6 +41,7 @@ use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
 use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
 use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
 use TYPO3\CMS\Core\Error\Http\ShortcutTargetPageNotFoundException;
+use TYPO3\CMS\Core\Exception\Page\RootLineException;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Locking\Exception\LockAcquireWouldBlockException;
 use TYPO3\CMS\Core\Locking\LockFactory;
@@ -60,6 +61,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Core\Utility\RootlineUtility;
 use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\Http\UrlHandlerInterface;
@@ -1479,20 +1481,24 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             // If no page, we try to find the page before in the rootLine.
             // Page is 'not found' in case the id itself was not an accessible page. code 1
             $this->pageNotFound = 1;
-            $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
-            if (!empty($this->rootLine)) {
-                $c = count($this->rootLine) - 1;
-                while ($c > 0) {
-                    // Add to page access failure history:
-                    $this->pageAccessFailureHistory['direct_access'][] = $this->rootLine[$c];
-                    // Decrease to next page in rootline and check the access to that, if OK, set as page record and ID value.
-                    $c--;
-                    $this->id = $this->rootLine[$c]['uid'];
-                    $this->page = $this->sys_page->getPage($this->id);
-                    if (!empty($this->page)) {
-                        break;
+            try {
+                $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
+                if (!empty($this->rootLine)) {
+                    $c = count($this->rootLine) - 1;
+                    while ($c > 0) {
+                        // Add to page access failure history:
+                        $this->pageAccessFailureHistory['direct_access'][] = $this->rootLine[$c];
+                        // Decrease to next page in rootline and check the access to that, if OK, set as page record and ID value.
+                        $c--;
+                        $this->id = $this->rootLine[$c]['uid'];
+                        $this->page = $this->sys_page->getPage($this->id);
+                        if (!empty($this->page)) {
+                            break;
+                        }
                     }
                 }
+            } catch (RootLineException $e) {
+                $this->rootLine = [];
             }
             // If still no page...
             if (empty($this->page)) {
@@ -1552,7 +1558,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             $this->id = $this->page['uid'];
         }
         // Gets the rootLine
-        $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
+        try {
+            $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
+        } catch (RootLineException $e) {
+            $this->rootLine = [];
+        }
         // If not rootline we're off...
         if (empty($this->rootLine)) {
             $message = 'The requested page didn\'t have a proper connection to the tree-root!';
@@ -1587,7 +1597,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
                 $el = reset($this->rootLine);
                 $this->id = $el['uid'];
                 $this->page = $this->sys_page->getPage($this->id);
-                $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
+                try {
+                    $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
+                } catch (RootLineException $e) {
+                    $this->rootLine = [];
+                }
             }
         }
     }
@@ -2754,7 +2768,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      */
     protected function updateRootLinesWithTranslations()
     {
-        $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
+        try {
+            $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
+        } catch (RootLineException $e) {
+            $this->rootLine = [];
+        }
         $this->tmpl->updateRootlineData($this->rootLine);
     }
 
@@ -4692,15 +4710,19 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         if (!array_key_exists($targetPid, $this->domainDataCache)) {
             $result = null;
             $sysDomainData = $this->getSysDomainCache();
-            $rootline = $this->sys_page->getRootLine($targetPid);
-            // walk the rootline downwards from the target page
-            // to the root page, until a domain record is found
-            foreach ($rootline as $pageInRootline) {
-                $pidInRootline = $pageInRootline['uid'];
-                if (isset($sysDomainData[$pidInRootline])) {
-                    $result = $sysDomainData[$pidInRootline];
-                    break;
+            try {
+                $rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $targetPid, null, $this->context)->get();
+                // walk the rootline downwards from the target page
+                // to the root page, until a domain record is found
+                foreach ($rootLine as $pageInRootline) {
+                    $pidInRootline = $pageInRootline['uid'];
+                    if (isset($sysDomainData[$pidInRootline])) {
+                        $result = $sysDomainData[$pidInRootline];
+                        break;
+                    }
                 }
+            } catch (RootLineException $e) {
+                // Do nothing
             }
             $this->domainDataCache[$targetPid] = $result;
         }
index c667142..e527401 100644 (file)
@@ -1114,14 +1114,11 @@ class PageRepository implements LoggerAwareInterface
      * @throws \RuntimeException
      * @return array Array with page records from the root line as values. The array is ordered with the outer records first and root record in the bottom. The keys are numeric but in reverse order. So if you traverse/sort the array by the numeric keys order you will get the order from root and out. If an error is found (like eternal looping or invalid mountpoint) it will return an empty array.
      * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::getPageAndRootline()
+     * @deprecated since TYPO3 v10.0.
      */
     public function getRootLine($uid, $MP = '', $ignoreMPerrors = null)
     {
-        if ($ignoreMPerrors !== null) {
-            trigger_error('The third argument in PageRepository::getRootline() will be removed in TYPO3 v10.0. Use a try/catch block around this method to catch any mount point errors, if necessary', E_USER_DEPRECATED);
-        } else {
-            $ignoreMPerrors = false;
-        }
+        trigger_error('Calling PageRepository->getRootLine() will be removed in TYPO3 v10.0. Use RootlineUtility directly.', E_USER_DEPRECATED);
         $rootline = GeneralUtility::makeInstance(RootlineUtility::class, $uid, $MP, $this->context);
         try {
             return $rootline->get();
index 85a713d..1399019 100644 (file)
@@ -20,9 +20,11 @@ use TYPO3\CMS\Backend\Routing\PageUriBuilder;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Exception\Page\RootLineException;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Core\Utility\RootlineUtility;
 use TYPO3\CMS\Frontend\ContentObject\TypolinkModifyLinkConfigForPageLinksHookInterface;
 use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
 use TYPO3\CMS\Frontend\Page\PageRepository;
@@ -294,8 +296,8 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
         // Find closest mount point
         // Gets rootline of linked-to page
         try {
-            $tCR_rootline = $tsfe->sys_page->getRootLine($pageId);
-        } catch (\RuntimeException $e) {
+            $tCR_rootline = GeneralUtility::makeInstance(RootlineUtility::class, $pageId)->get();
+        } catch (RootLineException $e) {
             $tCR_rootline = [];
         }
         $inverseTmplRootline = array_reverse($tsfe->tmpl->rootLine);
index 6fb0cc8..e6a9f19 100644 (file)
@@ -412,12 +412,11 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
             ->getMock();
         $pageRepositoryMockObject->expects($this->any())->method('getPage')->willReturn($pageArray);
 
-        $typoScriptFrontendController = GeneralUtility::makeInstance(
-            TypoScriptFrontendController::class,
-            null,
-            1,
-            0
-        );
+        $typoScriptFrontendController = $this->getMockBuilder(TypoScriptFrontendController::class)
+            ->setConstructorArgs([null, 1, 0])
+            ->setMethods(['getDomainDataForPid'])
+            ->getMock();
+        $typoScriptFrontendController->expects($this->any())->method('getDomainDataForPid')->willReturn(null);
         $typoScriptFrontendController->config = [
             'config' => [],
         ];
@@ -472,12 +471,11 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
         ]);
         GeneralUtility::addInstance(PageLinkBuilder::class, $pageLinkBuilder);
 
-        $typoScriptFrontendController = GeneralUtility::makeInstance(
-            TypoScriptFrontendController::class,
-            null,
-            1,
-            0
-        );
+        $typoScriptFrontendController = $this->getMockBuilder(TypoScriptFrontendController::class)
+            ->setConstructorArgs([null, 1, 0])
+            ->setMethods(['getDomainDataForPid'])
+            ->getMock();
+        $typoScriptFrontendController->expects($this->any())->method('getDomainDataForPid')->willReturn(null);
         $typoScriptFrontendController->config = [
             'config' => [],
         ];
index 9afbacd..b22a4c5 100644 (file)
@@ -19,6 +19,7 @@ use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
+use TYPO3\CMS\Core\Exception\Page\RootLineException;
 use TYPO3\CMS\Core\Html\HtmlParser;
 use TYPO3\CMS\Core\Type\File\ImageInfo;
 use TYPO3\CMS\Core\TypoScript\TypoScriptService;
@@ -26,6 +27,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\IpAnonymizationUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Core\Utility\RootlineUtility;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
 
 /**
@@ -577,9 +579,9 @@ class SearchController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControlle
     {
         $pathId = $row['data_page_id'] ?: $row['page_id'];
         $pathMP = $row['data_page_id'] ? $row['data_page_mp'] : '';
-        $rl = $GLOBALS['TSFE']->sys_page->getRootLine($pathId, $pathMP);
         $specConf = $this->settings['specialConfiguration']['0'];
-        if (is_array($rl)) {
+        try {
+            $rl = GeneralUtility::makeInstance(RootlineUtility::class, $pathId, $pathMP)->get();
             foreach ($rl as $dat) {
                 if (is_array($this->settings['specialConfiguration'][$dat['uid']])) {
                     $specConf = $this->settings['specialConfiguration'][$dat['uid']];
@@ -587,6 +589,8 @@ class SearchController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControlle
                     break;
                 }
             }
+        } catch (RootLineException $e) {
+            // do nothing
         }
         return $specConf;
     }
@@ -1389,43 +1393,47 @@ class SearchController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControlle
         if (!isset($this->pathCache[$identStr])) {
             $this->requiredFrontendUsergroups[$id] = [];
             $this->domainRecords[$id] = [];
-            $rl = $GLOBALS['TSFE']->sys_page->getRootLine($id, $pathMP);
-            $path = '';
-            $pageCount = count($rl);
-            if (is_array($rl) && !empty($rl)) {
-                $excludeDoktypesFromPath = GeneralUtility::trimExplode(
-                    ',',
-                    $this->settings['results']['pathExcludeDoktypes'] ?? '',
-                    true
-                );
-                $breadcrumbWrap = $this->settings['breadcrumbWrap'] ?? '/';
-                $breadcrumbWraps = GeneralUtility::makeInstance(TypoScriptService::class)
-                    ->explodeConfigurationForOptionSplit(['wrap' => $breadcrumbWrap], $pageCount);
-                foreach ($rl as $k => $v) {
-                    if (in_array($v['doktype'], $excludeDoktypesFromPath, false)) {
-                        continue;
-                    }
-                    // Check fe_user
-                    if ($v['fe_group'] && ($v['uid'] == $id || $v['extendToSubpages'])) {
-                        $this->requiredFrontendUsergroups[$id][] = $v['fe_group'];
-                    }
-                    // Check sys_domain
-                    if ($this->settings['detectDomainRecords']) {
-                        $domainName = $this->getFirstSysDomainRecordForPage($v['uid']);
-                        if ($domainName) {
-                            $this->domainRecords[$id][] = $domainName;
-                            // Set path accordingly
-                            $path = $domainName . $path;
+            try {
+                $rl = GeneralUtility::makeInstance(RootlineUtility::class, $id, $pathMP)->get();
+                $path = '';
+                $pageCount = count($rl);
+                if (!empty($rl)) {
+                    $excludeDoktypesFromPath = GeneralUtility::trimExplode(
+                        ',',
+                        $this->settings['results']['pathExcludeDoktypes'] ?? '',
+                        true
+                    );
+                    $breadcrumbWrap = $this->settings['breadcrumbWrap'] ?? '/';
+                    $breadcrumbWraps = GeneralUtility::makeInstance(TypoScriptService::class)
+                        ->explodeConfigurationForOptionSplit(['wrap' => $breadcrumbWrap], $pageCount);
+                    foreach ($rl as $k => $v) {
+                        if (in_array($v['doktype'], $excludeDoktypesFromPath, false)) {
+                            continue;
+                        }
+                        // Check fe_user
+                        if ($v['fe_group'] && ($v['uid'] == $id || $v['extendToSubpages'])) {
+                            $this->requiredFrontendUsergroups[$id][] = $v['fe_group'];
+                        }
+                        // Check sys_domain
+                        if ($this->settings['detectDomainRecords']) {
+                            $domainName = $this->getFirstSysDomainRecordForPage($v['uid']);
+                            if ($domainName) {
+                                $this->domainRecords[$id][] = $domainName;
+                                // Set path accordingly
+                                $path = $domainName . $path;
+                                break;
+                            }
+                        }
+                        // Stop, if we find that the current id is the current root page.
+                        if ($v['uid'] == $GLOBALS['TSFE']->config['rootLine'][0]['uid']) {
+                            array_pop($breadcrumbWraps);
                             break;
                         }
+                        $path = $GLOBALS['TSFE']->cObj->wrap(htmlspecialchars($v['title']), array_pop($breadcrumbWraps)['wrap']) . $path;
                     }
-                    // Stop, if we find that the current id is the current root page.
-                    if ($v['uid'] == $GLOBALS['TSFE']->config['rootLine'][0]['uid']) {
-                        array_pop($breadcrumbWraps);
-                        break;
-                    }
-                    $path = $GLOBALS['TSFE']->cObj->wrap(htmlspecialchars($v['title']), array_pop($breadcrumbWraps)['wrap']) . $path;
                 }
+            } catch (RootLineException $e) {
+                $path = '';
             }
             $this->pathCache[$identStr] = $path;
         }
index d254f7a..0d2527a 100644 (file)
@@ -20,8 +20,10 @@ use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Exception\Page\RootLineException;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Core\Utility\RootlineUtility;
 
 /**
  * Crawler hook for indexed search. Works with the "crawler" extension
@@ -688,18 +690,21 @@ class CrawlerHook
      */
     public function getUidRootLineForClosestTemplate($id)
     {
-        $tmpl = GeneralUtility::makeInstance(\TYPO3\CMS\Core\TypoScript\ExtendedTemplateService::class);
-        // Gets the rootLine
-        $sys_page = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
-        $rootLine = $sys_page->getRootLine($id);
-        // This generates the constants/config + hierarchy info for the template.
-        $tmpl->runThroughTemplates($rootLine, 0);
-        // Root line uids
-        $rootline_uids = [];
-        foreach ($tmpl->rootLine as $rlkey => $rldat) {
-            $rootline_uids[$rlkey] = $rldat['uid'];
+        $rootLineUids = [];
+        try {
+            // Gets the rootLine
+            $rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $id)->get();
+            // This generates the constants/config + hierarchy info for the template.
+            $tmpl = GeneralUtility::makeInstance(\TYPO3\CMS\Core\TypoScript\ExtendedTemplateService::class);
+            $tmpl->runThroughTemplates($rootLine);
+            // Root line uids
+            foreach ($tmpl->rootLine as $rlkey => $rldat) {
+                $rootLineUids[$rlkey] = $rldat['uid'];
+            }
+        } catch (RootLineException $e) {
+            // do nothing
         }
-        return $rootline_uids;
+        return $rootLineUids;
     }
 
     /**
index e2472df..f881108 100644 (file)
@@ -177,10 +177,4 @@ return [
             'Breaking-84877-MethodsOfLocalizationRepositoryChanged.rst',
         ],
     ],
-    'TYPO3\CMS\Frontend\Page\PageRepository->getRootLine' => [
-        'maximumNumberOfArguments' => 2,
-        'restFiles' => [
-            'Deprecation-85105-3rdMethodArgumentInPageRepository-getRootLine.rst',
-        ],
-    ],
 ];
index 783d651..7f014b7 100644 (file)
@@ -2424,6 +2424,13 @@ return [
             'Deprecation-85445-TemplateService-getFileName.rst'
         ],
     ],
+    'TYPO3\CMS\Frontend\Page\PageRepository->getRootLine' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 3,
+        'restFiles' => [
+            'Deprecation-85557-PageRepository-getRootLine.rst'
+        ],
+    ],
     'TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->calcIntExplode' => [
         'numberOfMandatoryArguments' => 2,
         'maximumNumberOfArguments' => 2,
index 1b82e46..59ff6e2 100644 (file)
@@ -218,7 +218,7 @@ class ActionTest extends \TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\IRR
         $this->assertAssertionDataSet('deletePage');
 
         $response = $this->getFrontendResponse(self::VALUE_PageId, 0, self::VALUE_BackendUserId, self::VALUE_WorkspaceId, false);
-        $this->assertContains('RuntimeException', $response->getError());
+        $this->assertContains('PageNotFoundException', $response->getError());
     }
 
     /**
index f55f15c..da4199b 100644 (file)
@@ -218,7 +218,7 @@ class ActionTest extends \TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\IRR
         $this->assertAssertionDataSet('deletePage');
 
         $response = $this->getFrontendResponse(self::VALUE_PageId, 0, self::VALUE_BackendUserId, self::VALUE_WorkspaceId, false);
-        $this->assertContains('RuntimeException', $response->getError());
+        $this->assertContains('PageNotFoundException', $response->getError());
     }
 
     /**
index a282f5a..5481c65 100644 (file)
@@ -312,7 +312,7 @@ class ActionTest extends \TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\Reg
         $this->assertAssertionDataSet('deletePage');
 
         $response = $this->getFrontendResponse(self::VALUE_PageId, 0, self::VALUE_BackendUserId, self::VALUE_WorkspaceId, false);
-        $this->assertContains('RuntimeException', $response->getError());
+        $this->assertContains('PageNotFoundException', $response->getError());
     }
 
     /**
@@ -325,7 +325,7 @@ class ActionTest extends \TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\Reg
         $this->assertAssertionDataSet('deleteContentAndPage');
 
         $response = $this->getFrontendResponse(self::VALUE_PageId, 0, self::VALUE_BackendUserId, self::VALUE_WorkspaceId, false);
-        $this->assertContains('RuntimeException', $response->getError());
+        $this->assertContains('PageNotFoundException', $response->getError());
     }
 
     /**