[TASK] Move linkData() functionality in PageLinkBuilder 76/56576/5
authorBenni Mack <benni@typo3.org>
Fri, 6 Apr 2018 07:38:21 +0000 (09:38 +0200)
committerSusanne Moog <susanne.moog@typo3.org>
Fri, 6 Apr 2018 11:35:49 +0000 (13:35 +0200)
The "mother of building all links in Frontend" is moved
into PageLinkBuilder. Along with this, building a
mountPointMap is moved into the PageLinkBuilder as well,
as this is solely needed.

Existing methods are deprecated:
 * TemplateService->linkData
 * TemplateService->getFromMPmap
 * TemplateService->initMPmap_create

The existing hook is moved into PageLinkBuilder as well,
so functionality like RealURL will work the same.

Resolves: #84637
Releases: master
Change-Id: I513bd721a77ed8959f3c8b4bfc4eaa25dd05eacc
Reviewed-on: https://review.typo3.org/56576
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: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
typo3/sysext/core/Classes/TypoScript/TemplateService.php
typo3/sysext/core/Documentation/Changelog/master/Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst [new file with mode: 0644]
typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php
typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
typo3/sysext/frontend/Tests/Functional/ContentObject/ContentObjectRendererTest.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php

index 4c83259..3ecb690 100644 (file)
@@ -306,6 +306,7 @@ class TemplateService
 
     /**
      * Contains mapping of Page id numbers to MP variables.
+     * This is not used anymore, and will be removed in TYPO3 v10.
      *
      * @var string
      */
@@ -1478,9 +1479,11 @@ class TemplateService
      * @param string $targetDomain The target Doamin, if any was detected in typolink
      * @return array Contains keys like "totalURL", "url", "sectionIndex", "linkVars", "no_cache", "type", "target" of which "totalURL" is normally the value you would use while the other keys contains various parts that was used to construct "totalURL
      * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::typoLink(), \TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject::link()
+     * @deprecated - will be removed in TYPO3 v10.0 - have a look at PageLinkBuilder
      */
     public function linkData($page, $oTarget, $no_cache, $_ = null, $overrideArray = null, $addParams = '', $typeOverride = '', $targetDomain = '')
     {
+        trigger_error('Creating URLs to pages is now encapsulated into PageLinkBuilder, and should be used in the future. This method will be removed in TYPO3 v10.0', E_USER_DEPRECATED);
         $LD = [];
         // Overriding some fields in the page record and still preserves the values by adding them as parameters. Little strange function.
         if (is_array($overrideArray)) {
@@ -1562,9 +1565,11 @@ class TemplateService
      * @return string
      * @see initMPmap_create()
      * @todo Implement some caching of the result between hits. (more than just the memory caching used here)
+     * @deprecated - will be removed in TYPO3 v10.
      */
     public function getFromMPmap($pageId = 0)
     {
+        trigger_error('Getting a mount point parameter for a page is now built into PageLinkBuilder, and should be used in the future. This method will be removed in TYPO3 v10.0', E_USER_DEPRECATED);
         // Create map if not found already:
         if (!is_array($this->MPmap)) {
             $this->MPmap = [];
@@ -1597,9 +1602,11 @@ class TemplateService
      * @param array $MP_array MP_array passed from root page.
      * @param int $level Recursion brake. Incremented for each recursive call. 20 is the limit.
      * @see getFromMPvar()
+     * @deprecated will be removed in TYPO3 v10.0
      */
     public function initMPmap_create($id, $MP_array = [], $level = 0)
     {
+        trigger_error('Building a mount point parameter map is now built into PageLinkBuilder, and should be used in the future. This method will be removed in TYPO3 v10.0', E_USER_DEPRECATED);
         $id = (int)$id;
         if ($id <= 0) {
             return;
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst
new file mode 100644 (file)
index 0000000..0f3a9f0
--- /dev/null
@@ -0,0 +1,42 @@
+.. include:: ../../Includes.txt
+
+========================================================================================
+Deprecation: #84637 - TemplateService->linkData() functionality moved in PageLinkBuilder
+========================================================================================
+
+See :issue:`84637`
+
+Description
+===========
+
+In the process of streamlining the link generation to pages in the Frontend, the master method
+:php:`TemplateService->linkData` and all functionality regarding resolving of the according Mount Point parameters
+have been migrated into the TypoLink PageLinkBuilder class.
+
+The following methods have been marked as deprecated:
+* :php:`TYPO3\CMS\Core\TypoScript\TemplateService->linkData`
+* :php:`TYPO3\CMS\Core\TypoScript\TemplateService->getFromMPmap`
+* :php:`TYPO3\CMS\Core\TypoScript\TemplateService->initMPmap_create`
+
+
+Impact
+======
+
+Calling any of the methods above will trigger a PHP deprecation message.
+
+
+Affected Installations
+======================
+
+Any TYPO3 installations with third-party extensions calling the methods directly, extensions using the
+existing hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc']`
+will work the same way.
+
+
+Migration
+=========
+
+Access the corresponding new methods within :php:`PageLinkBuilder` instead of the TemplateService-related
+methods, or use the existing hook to modify parameters for a URL.
+
+.. index:: FullyScanned
\ No newline at end of file
index 755e267..ede2443 100644 (file)
@@ -26,6 +26,7 @@ use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
 use TYPO3\CMS\Frontend\Page\PageRepository;
+use TYPO3\CMS\Frontend\Typolink\PageLinkBuilder;
 
 /**
  * Generating navigation/menus from TypoScript
@@ -708,14 +709,15 @@ abstract class AbstractMenuContentObject
             $specialValue = $tsfe->page['uid'];
         }
         $items = GeneralUtility::intExplode(',', $specialValue);
+        $pageLinkBuilder = GeneralUtility::makeInstance(PageLinkBuilder::class, $this->parent_cObj);
         foreach ($items as $id) {
-            $MP = $this->tmpl->getFromMPmap($id);
+            $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps($id);
             // Checking if a page is a mount page and if so, change the ID and set the MP var properly.
             $mount_info = $this->sys_page->getMountPointInfo($id);
             if (is_array($mount_info)) {
                 if ($mount_info['overlay']) {
                     // Overlays should already have their full MPvars calculated:
-                    $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']);
+                    $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps((int)$mount_info['mount_pid']);
                     $MP = $MP ? $MP : $mount_info['MPvar'];
                 } else {
                     $MP = ($MP ? $MP . ',' : '') . $mount_info['MPvar'];
@@ -779,8 +781,9 @@ abstract class AbstractMenuContentObject
         $loadDB->start($specialValue, 'pages');
         $loadDB->additionalWhere['pages'] = $this->parent_cObj->enableFields('pages', false, $skippedEnableFields);
         $loadDB->getFromDB();
+        $pageLinkBuilder = GeneralUtility::makeInstance(PageLinkBuilder::class, $this->parent_cObj);
         foreach ($loadDB->itemArray as $val) {
-            $MP = $this->tmpl->getFromMPmap($val['id']);
+            $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps((int)$val['id']);
             // Keep mount point?
             $mount_info = $this->sys_page->getMountPointInfo($val['id']);
             // There is a valid mount point.
@@ -793,7 +796,7 @@ abstract class AbstractMenuContentObject
                     $row['_MP_PARAM'] = $mount_info['MPvar'];
                     // Overlays should already have their full MPvars calculated
                     if ($mount_info['overlay']) {
-                        $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']);
+                        $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps((int)$mount_info['mount_pid']);
                         if ($MP) {
                             unset($row['_MP_PARAM']);
                         }
index be1cbb8..cc7376d 100644 (file)
@@ -15,6 +15,8 @@ namespace TYPO3\CMS\Frontend\Typolink;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Frontend\ContentObject\TypolinkModifyLinkConfigForPageLinksHookInterface;
@@ -178,7 +180,6 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
         // If target page has a different domain and the current domain's linking scheme (e.g. RealURL/...) should not be used
         if ($targetDomain !== '' && $targetDomain !== $currentDomain && !$enableLinksAcrossDomains) {
             $target = $target ?: $this->resolveTargetAttribute($conf, 'extTarget', false, $tsfe->extTarget);
-            $LD['target'] = $target;
             // Convert IDNA-like domain (if any)
             if (!preg_match('/^[a-z0-9.\\-]*$/i', $targetDomain)) {
                 $targetDomain = GeneralUtility::idnaEncode($targetDomain);
@@ -187,10 +188,11 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
         } else {
             // Internal link or current domain's linking scheme should be used
             // Internal target:
+            $target = (isset($page['target']) && trim($page['target'])) ? $page['target'] : $target;
             if (empty($target)) {
                 $target = $this->resolveTargetAttribute($conf, 'target', true, $tsfe->intTarget);
             }
-            $LD = $tsfe->tmpl->linkData($page, $target, $conf['no_cache'], '', '', $addQueryParams, $pageType, $targetDomain);
+            $LD = $this->createTotalUrlAndLinkData($page, $target, $conf['no_cache'], $addQueryParams, $pageType, $targetDomain);
             if ($targetDomain !== '') {
                 // We will add domain only if URL does not have it already.
                 if ($enableLinksAcrossDomains && $targetDomain !== $currentDomain && isset($tsfe->config['config']['absRefPrefix'])) {
@@ -210,7 +212,6 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
             }
             $url = $LD['totalURL'] . $sectionMark;
         }
-        $target = $LD['target'];
         // If sectionMark is set, there is no baseURL AND the current page is the page the link is to, check if there are any additional parameters or addQueryString parameters and if not, drop the url.
         if ($sectionMark
             && !$tsfe->config['config']['baseURL']
@@ -312,4 +313,228 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
         }
         return !empty($rl_mpArray) ? implode(',', array_reverse($rl_mpArray)) : '';
     }
+
+    /**
+     * Initializes the automatically created mountPointMap coming from the "config.MP_mapRootPoints" setting
+     * Can be called many times with overhead only the first time since then the map is generated and cached in memory.
+     *
+     * Previously located within TemplateService::getFromMPmap()
+     *
+     * @param int $pageId Page id to return MPvar value for.
+     * @return string
+     */
+    public function getMountPointParameterFromRootPointMaps(int $pageId)
+    {
+        // Create map if not found already
+        $mountPointMap = $this->initializeMountPointMap(
+            $this->getTypoScriptFrontendController()->config['config']['MP_defaults'] ?: null,
+            $this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints'] ?: null
+        );
+
+        // Finding MP var for Page ID:
+        if (is_array($mountPointMap[$pageId]) && !empty($mountPointMap[$pageId])) {
+            return implode(',', $mountPointMap[$pageId]);
+        }
+        return '';
+    }
+
+    /**
+     * Create mount point map, based on TypoScript config.MP_mapRootPoints and config.MP_defaults.
+     *
+     * @param string $defaultMountPoints a string as defined in config.MP_defaults
+     * @param string|null $mapRootPointList a string as defined in config.MP_mapRootPoints
+     * @return array
+     */
+    protected function initializeMountPointMap(string $defaultMountPoints = null, string $mapRootPointList = null): array
+    {
+        static $mountPointMap = [];
+        if (!empty($mountPointMap) || (empty($mapRootPointList) && empty($defaultMountPoints))) {
+            return $mountPointMap;
+        }
+        if ($defaultMountPoints) {
+            $defaultMountPoints = GeneralUtility::trimExplode('|', $defaultMountPoints, true);
+            foreach ($defaultMountPoints as $temp_p) {
+                list($temp_idP, $temp_MPp) = explode(':', $temp_p, 2);
+                $temp_ids = GeneralUtility::intExplode(',', $temp_idP);
+                foreach ($temp_ids as $temp_id) {
+                    $mountPointMap[$temp_id] = trim($temp_MPp);
+                }
+            }
+        }
+
+        $rootPoints = GeneralUtility::trimExplode(',', strtolower($mapRootPointList), true);
+        // Traverse rootpoints
+        foreach ($rootPoints as $p) {
+            $initMParray = [];
+            if ($p === 'root') {
+                $rootPage = $this->getTypoScriptFrontendController()->tmpl->rootLine[0];
+                $p = $rootPage['uid'];
+                if ($p['_MOUNT_OL'] && $p['_MP_PARAM']) {
+                    $initMParray[] = $p['_MP_PARAM'];
+                }
+            }
+            $this->populateMountPointMapForPageRecursively($mountPointMap, $p, $initMParray);
+        }
+        return $mountPointMap;
+    }
+
+    /**
+     * Creating mountPointMap for a certain ID root point.
+     * Previously called TemplateService->initMPmap_create()
+     *
+     * @param array $mountPointMap the exiting mount point map
+     * @param int $id Root id from which to start map creation.
+     * @param array $MP_array MP_array passed from root page.
+     * @param int $level Recursion brake. Incremented for each recursive call. 20 is the limit.
+     * @see getMountPointParameterFromRootPointMaps()
+     */
+    protected function populateMountPointMapForPageRecursively(array &$mountPointMap, int $id, $MP_array = [], $level = 0)
+    {
+        if ($id <= 0) {
+            return;
+        }
+        // First level, check id
+        if (!$level) {
+            // Find mount point if any:
+            $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($id);
+            // Overlay mode:
+            if (is_array($mount_info) && $mount_info['overlay']) {
+                $MP_array[] = $mount_info['MPvar'];
+                $id = $mount_info['mount_pid'];
+            }
+            // Set mapping information for this level:
+            $mountPointMap[$id] = $MP_array;
+            // Normal mode:
+            if (is_array($mount_info) && !$mount_info['overlay']) {
+                $MP_array[] = $mount_info['MPvar'];
+                $id = $mount_info['mount_pid'];
+            }
+        }
+        if ($id && $level < 20) {
+            $nextLevelAcc = [];
+            // Select and traverse current level pages:
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
+            $queryBuilder->getRestrictions()
+                ->removeAll()
+                ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
+            $queryResult = $queryBuilder
+                ->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol')
+                ->from('pages')
+                ->where(
+                    $queryBuilder->expr()->eq(
+                        'pid',
+                        $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
+                    ),
+                    $queryBuilder->expr()->neq(
+                        'doktype',
+                        $queryBuilder->createNamedParameter(PageRepository::DOKTYPE_RECYCLER, \PDO::PARAM_INT)
+                    ),
+                    $queryBuilder->expr()->neq(
+                        'doktype',
+                        $queryBuilder->createNamedParameter(PageRepository::DOKTYPE_BE_USER_SECTION, \PDO::PARAM_INT)
+                    )
+                )->execute();
+            while ($row = $queryResult->fetch()) {
+                // Find mount point if any:
+                $next_id = $row['uid'];
+                $next_MP_array = $MP_array;
+                $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($next_id, $row);
+                // Overlay mode:
+                if (is_array($mount_info) && $mount_info['overlay']) {
+                    $next_MP_array[] = $mount_info['MPvar'];
+                    $next_id = $mount_info['mount_pid'];
+                }
+                if (!isset($mountPointMap[$next_id])) {
+                    // Set mapping information for this level:
+                    $mountPointMap[$next_id] = $next_MP_array;
+                    // Normal mode:
+                    if (is_array($mount_info) && !$mount_info['overlay']) {
+                        $next_MP_array[] = $mount_info['MPvar'];
+                        $next_id = $mount_info['mount_pid'];
+                    }
+                    // Register recursive call
+                    // (have to do it this way since ALL of the current level should be registered BEFORE the sublevel at any time)
+                    $nextLevelAcc[] = [$next_id, $next_MP_array];
+                }
+            }
+            // Call recursively, if any:
+            foreach ($nextLevelAcc as $pSet) {
+                $this->populateMountPointMapForPageRecursively($mountPointMap, $pSet[0], $pSet[1], $level + 1);
+            }
+        }
+    }
+
+    /**
+     * The mother of all functions creating links/URLs etc in a TypoScript environment.
+     * See the references below.
+     * Basically this function takes care of issues such as type,id,alias and Mount Points, URL rewriting (through hooks), M5/B6 encoded parameters etc.
+     * It is important to pass all links created through this function since this is the guarantee that globally configured settings for link creating are observed and that your applications will conform to the various/many configuration options in TypoScript Templates regarding this.
+     *
+     * @param array $page The page record of the page to which we are creating a link. Needed due to fields like uid, alias, target, title and sectionIndex_uid.
+     * @param string $target Target string
+     * @param bool $no_cache If set, then the "&no_cache=1" parameter is included in the URL.
+     * @param string $addParams Additional URL parameters to set in the URL. Syntax is "&foo=bar&foo2=bar2" etc. Also used internally to add parameters if needed.
+     * @param string $typeOverride If you set this value to something else than a blank string, then the typeNumber used in the link will be forced to this value. Normally the typeNum is based on the target set OR on $this->getTypoScriptFrontendController()->config['config']['forceTypeValue'] if found.
+     * @param string $targetDomain The target Doamin, if any was detected in typolink
+     * @return array Contains keys like "totalURL", "url", "sectionIndex", "linkVars", "no_cache", "type" of which "totalURL" is normally the value you would use while the other keys contains various parts that was used to construct "totalURL
+     */
+    protected function createTotalUrlAndLinkData($page, $target, $no_cache, $addParams = '', $typeOverride = '', $targetDomain = '')
+    {
+        $LD = [];
+        // Adding Mount Points, "&MP=", parameter for the current page if any is set
+        // but non other set explicitly
+        if (strpos($addParams, '&MP=') === false) {
+            $mountPointParameter = $this->getMountPointParameterFromRootPointMaps((int)$page['uid']);
+            if ($mountPointParameter) {
+                $addParams .= '&MP=' . rawurlencode($mountPointParameter);
+            }
+        }
+        // Setting ID/alias:
+        $script = 'index.php';
+        if ($page['alias']) {
+            $LD['url'] = $script . '?id=' . rawurlencode($page['alias']);
+        } else {
+            $LD['url'] = $script . '?id=' . $page['uid'];
+        }
+        // typeNum
+        $typeNum = $this->getTypoScriptFrontendController()->tmpl->setup[$target . '.']['typeNum'];
+        if (!MathUtility::canBeInterpretedAsInteger($typeOverride) && (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue']) {
+            $typeOverride = (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue'];
+        }
+        if ((string)$typeOverride !== '') {
+            $typeNum = $typeOverride;
+        }
+        // Override...
+        if ($typeNum) {
+            $LD['type'] = '&type=' . (int)$typeNum;
+        } else {
+            $LD['type'] = '';
+        }
+        // Preserving the type number.
+        $LD['orig_type'] = $LD['type'];
+        // noCache
+        $LD['no_cache'] = $no_cache ? '&no_cache=1' : '';
+        // linkVars
+        if ($addParams) {
+            $LD['linkVars'] = GeneralUtility::implodeArrayForUrl('', GeneralUtility::explodeUrl2Array($this->getTypoScriptFrontendController()->linkVars . $addParams), '', false, true);
+        } else {
+            $LD['linkVars'] = $this->getTypoScriptFrontendController()->linkVars;
+        }
+        // Add absRefPrefix if exists.
+        $LD['url'] = $this->getTypoScriptFrontendController()->absRefPrefix . $LD['url'];
+        // If the special key 'sectionIndex_uid' (added 'manually' in tslib/menu.php to the page-record) is set, then the link jumps directly to a section on the page.
+        $LD['sectionIndex'] = $page['sectionIndex_uid'] ? '#c' . $page['sectionIndex_uid'] : '';
+        // Compile the normal total url
+        $LD['totalURL'] = rtrim($LD['url'] . $LD['type'] . $LD['no_cache'] . $LD['linkVars'] . $this->getTypoScriptFrontendController()->getMethodUrlIdToken, '?') . $LD['sectionIndex'];
+        // Call post processing function for link rendering:
+        $_params = [
+            'LD' => &$LD,
+            'args' => ['page' => $page, 'oTarget' => $target, 'no_cache' => $no_cache, 'script' => $script, 'addParams' => $addParams, 'typeOverride' => $typeOverride, 'targetDomain' => $targetDomain],
+            'typeNum' => $typeNum
+        ];
+        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'] ?? [] as $_funcRef) {
+            GeneralUtility::callUserFunction($_funcRef, $_params, $this->getTypoScriptFrontendController()->tmpl);
+        }
+        return $LD;
+    }
 }
index a95dd27..88448d6 100644 (file)
@@ -20,6 +20,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Page\PageRepository;
+use TYPO3\CMS\Frontend\Typolink\PageLinkBuilder;
 
 /**
  * Testcase for TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
@@ -448,14 +449,19 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
         ]);
 
         $templateServiceMockObject = $this->getMockBuilder(TemplateService::class)
-            ->setMethods(['linkData'])
             ->getMock();
         $templateServiceMockObject->setup = [
             'lib.' => [
                 'parseFunc.' => $this->getLibParseFunc(),
             ],
         ];
-        $templateServiceMockObject->expects($this->once())->method('linkData')->willReturn([
+
+        $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
+        $pageLinkBuilder = $this->getMockBuilder(PageLinkBuilder::class)
+            ->setMethods(['createTotalUrlAndLinkData'])
+            ->setConstructorArgs([$subject])
+            ->getMock();
+        $pageLinkBuilder->expects($this::once())->method('createTotalUrlAndLinkData')->willReturn([
             'url' => '/index.php?id=1',
             'target' => '',
             'type' => '',
@@ -465,6 +471,7 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
             'sectionIndex' => '',
             'totalURL' => '/',
         ]);
+        GeneralUtility::addInstance(PageLinkBuilder::class, $pageLinkBuilder);
 
         $typoScriptFrontendController = GeneralUtility::makeInstance(
             TypoScriptFrontendController::class,
@@ -484,7 +491,6 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\
             'section' => 'content',
         ];
 
-        $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
         $this->assertEquals('<a href="#content">Page title</a>', $subject->typoLink('', $configuration));
     }
 
index b40bd02..4e622a6 100644 (file)
@@ -2060,4 +2060,25 @@ return [
             'Deprecation-84549-DeprecateMethodsInCoreVersionService.rst',
         ],
     ],
+    'TYPO3\CMS\Core\TypoScript\TemplateService->linkData' => [
+        'numberOfMandatoryArguments' => 3,
+        'maximumNumberOfArguments' => 8,
+        'restFiles' => [
+            'Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst',
+        ],
+    ],
+    'TYPO3\CMS\Core\TypoScript\TemplateService->getFromMPmap' => [
+        'numberOfMandatoryArguments' => 3,
+        'maximumNumberOfArguments' => 8,
+        'restFiles' => [
+            'Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst',
+        ],
+    ],
+    'TYPO3\CMS\Core\TypoScript\TemplateService->initMPmap_create' => [
+        'numberOfMandatoryArguments' => 3,
+        'maximumNumberOfArguments' => 8,
+        'restFiles' => [
+            'Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst',
+        ],
+    ],
 ];