From c262bec508d35c868095969f1e71be5989628934 Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Thu, 31 May 2018 20:40:04 +0200
Subject: [PATCH] [TASK] Move TSFE->getPageShortcut to PageRepository

The method `getPageShortcut()` which is marked as private is moved to
PageRepository, as it only requires logic and methods from
PageRepository.

Resolves: #85130
Releases: master
Change-Id: I4c7296e085953377e0937b8d1efad0b97d1fb021
Reviewed-on: https://review.typo3.org/57106
Reviewed-by: Mathias Brodala <mbrodala@pagemachine.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
---
 ...E-getPageShortcutMovedToPageRepository.rst | 35 +++++++++
 .../Menu/AbstractMenuContentObject.php        |  2 +-
 .../TypoScriptFrontendController.php          | 64 ++-------------
 .../frontend/Classes/Page/PageRepository.php  | 78 ++++++++++++++++++-
 .../Php/MethodCallMatcher.php                 |  9 ++-
 5 files changed, 126 insertions(+), 62 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-85130-TSFE-getPageShortcutMovedToPageRepository.rst

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-85130-TSFE-getPageShortcutMovedToPageRepository.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-85130-TSFE-getPageShortcutMovedToPageRepository.rst
new file mode 100644
index 000000000000..bd86f600fe1f
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-85130-TSFE-getPageShortcutMovedToPageRepository.rst
@@ -0,0 +1,35 @@
+.. include:: ../../Includes.txt
+
+======================================================================
+Deprecation: #85130 - $TSFE->getPageShortcut() moved to PageRepository
+======================================================================
+
+See :issue:`85130`
+
+Description
+===========
+
+The method :php:`TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::getPageShortcut()` has been
+moved to :php:`TYPO3\CMS\Frontend\Page\PageRepository::getPageShortcut()`, as it conceptually belongs in
+this class.
+
+
+Impact
+======
+
+Calling the method will trigger a deprecation message.
+
+
+Affected Installations
+======================
+
+TYPO3 installations using the method directly in an extension.
+
+
+Migration
+=========
+
+Switch the call :php:`$GLOBALS['TSFE']->getPageShortcut()` to :php:`$GLOBALS['TSFE']->sys_page->getPageShortcut()` to receive the exact
+same result without a deprecation message.
+
+.. index:: Frontend, PHP-API, PartiallyScanned
diff --git a/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php b/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php
index d9ea71018a4c..fbae0f3b178b 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php
@@ -1657,7 +1657,7 @@ abstract class AbstractMenuContentObject
         if ($this->menuArr[$key]['doktype'] == PageRepository::DOKTYPE_SHORTCUT && $this->menuArr[$key]['shortcut_mode'] != PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
             $menuItem = $this->determineOriginalShortcutPage($this->menuArr[$key]);
             try {
-                $shortcut = $tsfe->getPageShortcut(
+                $shortcut = $tsfe->sys_page->getPageShortcut(
                     $menuItem['shortcut'],
                     $menuItem['shortcut_mode'],
                     $menuItem['uid'],
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index e005d0a9b925..5014b517b7f2 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -1444,7 +1444,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             // whether a translation of the page overwrites the shortcut
             // target and we need to follow the new target
             $this->originalShortcutPage = $this->page;
-            $this->page = $this->getPageShortcut($this->page['shortcut'], $this->page['shortcut_mode'], $this->page['uid']);
+            $this->page = $this->sys_page->getPageShortcut($this->page['shortcut'], $this->page['shortcut_mode'], $this->page['uid']);
             $this->id = $this->page['uid'];
         }
         // If the page is a mountpoint which should be overlaid with the contents of the mounted page,
@@ -1516,7 +1516,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
     }
 
     /**
-     * Get page shortcut; Finds the records pointed to by input value $SC (the shortcut value)
+     * Get page shortcut; Finds the records pointed to by input value $SC (the shortcut value).
      *
      * @param int $SC The value of the "shortcut" field from the pages record
      * @param int $mode The shortcut mode: 1 will select first subpage, 2 a random subpage, 3 the parent page; default is the page pointed to by $SC
@@ -1529,64 +1529,12 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      * @return mixed Returns the page record of the page that the shortcut pointed to.
      * @access private
      * @see getPageAndRootline()
+     * @deprecated As this method conceptually belongs to PageRepository, it is moved in PageRepository, and will be removed in TYPO3 v10.0.
      */
     public function getPageShortcut($SC, $mode, $thisUid, $itera = 20, $pageLog = [], $disableGroupCheck = false)
     {
-        $idArray = GeneralUtility::intExplode(',', $SC);
-        // Find $page record depending on shortcut mode:
-        switch ($mode) {
-            case PageRepository::SHORTCUT_MODE_FIRST_SUBPAGE:
-
-            case PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE:
-                $pageArray = $this->sys_page->getMenu($idArray[0] ? $idArray[0] : $thisUid, '*', 'sorting', 'AND pages.doktype<199 AND pages.doktype!=' . PageRepository::DOKTYPE_BE_USER_SECTION);
-                $pO = 0;
-                if ($mode == PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE && !empty($pageArray)) {
-                    $randval = (int)rand(0, count($pageArray) - 1);
-                    $pO = $randval;
-                }
-                $c = 0;
-                $page = [];
-                foreach ($pageArray as $pV) {
-                    if ($c === $pO) {
-                        $page = $pV;
-                        break;
-                    }
-                    $c++;
-                }
-                if (empty($page)) {
-                    $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a subpage. ' . 'However, this page has no accessible subpages.';
-                    throw new ShortcutTargetPageNotFoundException($message, 1301648328);
-                }
-                break;
-            case PageRepository::SHORTCUT_MODE_PARENT_PAGE:
-                $parent = $this->sys_page->getPage($idArray[0] ? $idArray[0] : $thisUid, $disableGroupCheck);
-                $page = $this->sys_page->getPage($parent['pid'], $disableGroupCheck);
-                if (empty($page)) {
-                    $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to its parent page. ' . 'However, the parent page is not accessible.';
-                    throw new ShortcutTargetPageNotFoundException($message, 1301648358);
-                }
-                break;
-            default:
-                $page = $this->sys_page->getPage($idArray[0], $disableGroupCheck);
-                if (empty($page)) {
-                    $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a page, which is not accessible (ID ' . $idArray[0] . ').';
-                    throw new ShortcutTargetPageNotFoundException($message, 1301648404);
-                }
-        }
-        // Check if short cut page was a shortcut itself, if so look up recursively:
-        if ($page['doktype'] == PageRepository::DOKTYPE_SHORTCUT) {
-            if (!in_array($page['uid'], $pageLog) && $itera > 0) {
-                $pageLog[] = $page['uid'];
-                $page = $this->getPageShortcut($page['shortcut'], $page['shortcut_mode'], $page['uid'], $itera - 1, $pageLog, $disableGroupCheck);
-            } else {
-                $pageLog[] = $page['uid'];
-                $message = 'Page shortcuts were looping in uids ' . implode(',', $pageLog) . '...!';
-                $this->logger->error($message);
-                throw new \RuntimeException($message, 1294587212);
-            }
-        }
-        // Return resulting page:
-        return $page;
+        trigger_error('Method "TypoScriptFrontendController::getPageShortcut()" as been moved to PageRepository - use the page repository directly to call this functionality, as this method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
+        return $this->sys_page->getPageShortcut($SC, $mode, $thisUid, $itera, $pageLog, $disableGroupCheck);
     }
 
     /**
@@ -2731,7 +2679,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             if (!empty($originalShortcutPageOverlay['shortcut']) && $originalShortcutPageOverlay['shortcut'] != $this->id) {
                 // the translation of the original shortcut page has a different shortcut target!
                 // set the correct page and id
-                $shortcut = $this->getPageShortcut($originalShortcutPageOverlay['shortcut'], $originalShortcutPageOverlay['shortcut_mode'], $originalShortcutPageOverlay['uid']);
+                $shortcut = $this->sys_page->getPageShortcut($originalShortcutPageOverlay['shortcut'], $originalShortcutPageOverlay['shortcut_mode'], $originalShortcutPageOverlay['uid']);
                 $this->id = ($this->contentPid = $shortcut['uid']);
                 $this->page = $this->sys_page->getPage($this->id);
                 // Fix various effects on things like menus f.e.
diff --git a/typo3/sysext/frontend/Classes/Page/PageRepository.php b/typo3/sysext/frontend/Classes/Page/PageRepository.php
index 48e2fe8bc7b9..5c82755afadb 100644
--- a/typo3/sysext/frontend/Classes/Page/PageRepository.php
+++ b/typo3/sysext/frontend/Classes/Page/PageRepository.php
@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Database\Query\QueryHelper;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
 use TYPO3\CMS\Core\Database\Query\Restriction\FrontendWorkspaceRestriction;
+use TYPO3\CMS\Core\Error\Http\ShortcutTargetPageNotFoundException;
 use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
 use TYPO3\CMS\Core\Resource\FileRepository;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
@@ -654,7 +655,7 @@ class PageRepository implements LoggerAwareInterface
      * @param string $additionalWhereClause Optional additional where clauses. Like "AND title like '%blabla%'" for instance.
      * @param bool $checkShortcuts Check if shortcuts exist, checks by default
      * @return array Array with key/value pairs; keys are page-uid numbers. values are the corresponding page records (with overlaid localized fields, if any)
-     * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::getPageShortcut(), \TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject::makeMenu()
+     * @see self::getPageShortcut(), \TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject::makeMenu()
      */
     public function getMenu($pageId, $fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
     {
@@ -711,7 +712,7 @@ class PageRepository implements LoggerAwareInterface
      * @param bool $parentPages Switch to load pages (false) or child pages (true).
      * @return array page records
      *
-     * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::getPageShortcut()
+     * @see self::getPageShortcut()
      * @see \TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject::makeMenu()
      */
     protected function getSubpagesForPages(
@@ -883,6 +884,79 @@ class PageRepository implements LoggerAwareInterface
         return $page;
     }
 
+    /**
+     * Get page shortcut; Finds the records pointed to by input value $SC (the shortcut value)
+     *
+     * @param int $shortcutFieldValue The value of the "shortcut" field from the pages record
+     * @param int $shortcutMode The shortcut mode: 1 will select first subpage, 2 a random subpage, 3 the parent page; default is the page pointed to by $SC
+     * @param int $thisUid The current page UID of the page which is a shortcut
+     * @param int $iteration Safety feature which makes sure that the function is calling itself recursively max 20 times (since this function can find shortcuts to other shortcuts to other shortcuts...)
+     * @param array $pageLog An array filled with previous page uids tested by the function - new page uids are evaluated against this to avoid going in circles.
+     * @param bool $disableGroupCheck If true, the group check is disabled when fetching the target page (needed e.g. for menu generation)
+     *
+     * @throws \RuntimeException
+     * @throws ShortcutTargetPageNotFoundException
+     * @return mixed Returns the page record of the page that the shortcut pointed to.
+     * @access private
+     * @see getPageAndRootline()
+     */
+    public function getPageShortcut($shortcutFieldValue, $shortcutMode, $thisUid, $iteration = 20, $pageLog = [], $disableGroupCheck = false)
+    {
+        $idArray = GeneralUtility::intExplode(',', $shortcutFieldValue);
+        // Find $page record depending on shortcut mode:
+        switch ($shortcutMode) {
+            case self::SHORTCUT_MODE_FIRST_SUBPAGE:
+            case self::SHORTCUT_MODE_RANDOM_SUBPAGE:
+                $pageArray = $this->getMenu($idArray[0] ?: $thisUid, '*', 'sorting', 'AND pages.doktype<199 AND pages.doktype!=' . self::DOKTYPE_BE_USER_SECTION);
+                $pO = 0;
+                if ($shortcutMode == self::SHORTCUT_MODE_RANDOM_SUBPAGE && !empty($pageArray)) {
+                    $pO = (int)rand(0, count($pageArray) - 1);
+                }
+                $c = 0;
+                $page = [];
+                foreach ($pageArray as $pV) {
+                    if ($c === $pO) {
+                        $page = $pV;
+                        break;
+                    }
+                    $c++;
+                }
+                if (empty($page)) {
+                    $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a subpage. However, this page has no accessible subpages.';
+                    throw new ShortcutTargetPageNotFoundException($message, 1301648328);
+                }
+                break;
+            case self::SHORTCUT_MODE_PARENT_PAGE:
+                $parent = $this->getPage($idArray[0] ?: $thisUid, $disableGroupCheck);
+                $page = $this->getPage($parent['pid'], $disableGroupCheck);
+                if (empty($page)) {
+                    $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to its parent page. However, the parent page is not accessible.';
+                    throw new ShortcutTargetPageNotFoundException($message, 1301648358);
+                }
+                break;
+            default:
+                $page = $this->getPage($idArray[0], $disableGroupCheck);
+                if (empty($page)) {
+                    $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a page, which is not accessible (ID ' . $idArray[0] . ').';
+                    throw new ShortcutTargetPageNotFoundException($message, 1301648404);
+                }
+        }
+        // Check if short cut page was a shortcut itself, if so look up recursively:
+        if ($page['doktype'] == self::DOKTYPE_SHORTCUT) {
+            if (!in_array($page['uid'], $pageLog) && $iteration > 0) {
+                $pageLog[] = $page['uid'];
+                $page = $this->getPageShortcut($page['shortcut'], $page['shortcut_mode'], $page['uid'], $iteration - 1, $pageLog, $disableGroupCheck);
+            } else {
+                $pageLog[] = $page['uid'];
+                $message = 'Page shortcuts were looping in uids ' . implode(',', $pageLog) . '...!';
+                $this->logger->error($message);
+                throw new \RuntimeException($message, 1294587212);
+            }
+        }
+        // Return resulting page:
+        return $page;
+    }
+
     /**
      * Will find the page carrying the domain record matching the input domain.
      *
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
index 3eaa562f6e5c..60266cd5d3c5 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
@@ -2324,6 +2324,13 @@ return [
         'maximumNumberOfArguments' => 3,
         'restFiles' => [
             'Deprecation-85113-LegacyBackendModuleRoutingMethods.rst',
-        ]
+        ],
+    ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageShortcut' => [
+        'numberOfMandatoryArguments' => 3,
+        'maximumNumberOfArguments' => 6,
+        'restFiles' => [
+            'Deprecation-85130-TSFE-getPageShortcutMovedToPageRepository.rst',
+        ],
     ],
 ];
-- 
GitLab