From 886c2014bd6f37940da6630f1dbf584320628005 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Tue, 8 Nov 2022 13:22:10 +0100
Subject: [PATCH] [TASK] Actively deprecate TypoScript TemplateService
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

With last non-b/w compatibility related calls to
TypoScript/TemplateService being removed, we can
now actively deprecate method usages of this class.

The deprecation has been mentioned with v12.0 in
Breaking-97816-NewTypoScriptParserInFrontend.rst
already, the patch adds trigger_error() calls and
streamlines some left over comments. Another
ReST file is added pointing to the new Request
attribute added in Frontend context.

Resolves: #99020
Related: #98503
Related: #97816
Releases: main
Change-Id: Id01f4a4cb230f632f599e06ff4efe67fd53717c3
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/76477
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
---
 .../Parser/PageTsConfigParser.php             |  1 -
 .../Classes/TypoScript/TemplateService.php    | 42 ++++++++++++++++
 .../Utility/ExtensionManagementUtility.php    |  2 +-
 .../Configuration/DefaultConfiguration.php    |  2 +-
 ...020-DeprecateTypoScriptTemplateService.rst | 49 +++++++++++++++++++
 .../Fixtures/ext_typoscript_setup.typoscript  |  1 +
 .../TypoScript/TemplateServiceTest.php        |  2 +-
 .../TypoScriptFrontendController.php          |  1 -
 .../Classes/Typolink/PageLinkBuilder.php      |  3 --
 .../ExtensionScanner/Php/ClassNameMatcher.php |  6 +++
 .../t3editor/Resources/Private/tsref.xml      |  4 +-
 11 files changed, 103 insertions(+), 10 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/12.1/Deprecation-99020-DeprecateTypoScriptTemplateService.rst
 create mode 100644 typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Fixtures/ext_typoscript_setup.typoscript
 rename typo3/sysext/core/Tests/{Unit => UnitDeprecated}/TypoScript/TemplateServiceTest.php (98%)

diff --git a/typo3/sysext/core/Classes/Configuration/Parser/PageTsConfigParser.php b/typo3/sysext/core/Classes/Configuration/Parser/PageTsConfigParser.php
index 5c2f0b479568..6afc3e0ac7a1 100644
--- a/typo3/sysext/core/Classes/Configuration/Parser/PageTsConfigParser.php
+++ b/typo3/sysext/core/Classes/Configuration/Parser/PageTsConfigParser.php
@@ -62,7 +62,6 @@ class PageTsConfigParser
             }
             if (!empty($siteSettings)) {
                 // Recursive substitution of site settings (up to 10 nested levels)
-                // note: this code is more or less a duplicate of \TYPO3\CMS\Core\TypoScript\TemplateService::substituteConstants
                 for ($i = 0; $i < 10; $i++) {
                     $beforeSubstitution = $content;
                     $content = preg_replace_callback(
diff --git a/typo3/sysext/core/Classes/TypoScript/TemplateService.php b/typo3/sysext/core/Classes/TypoScript/TemplateService.php
index 67f8ba341a28..206135f1b49a 100644
--- a/typo3/sysext/core/Classes/TypoScript/TemplateService.php
+++ b/typo3/sysext/core/Classes/TypoScript/TemplateService.php
@@ -309,6 +309,8 @@ class TemplateService
      */
     protected $frontendController;
 
+    private static bool $deprecationLogged = false;
+
     /**
      * @param Context|null $context
      * @param PackageManager|null $packageManager
@@ -332,6 +334,10 @@ class TemplateService
      */
     public function getProcessExtensionStatics()
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         return $this->processExtensionStatics;
     }
 
@@ -340,6 +346,10 @@ class TemplateService
      */
     public function setProcessExtensionStatics($processExtensionStatics)
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         $this->processExtensionStatics = (bool)$processExtensionStatics;
     }
 
@@ -349,6 +359,10 @@ class TemplateService
      */
     public function setVerbose($verbose)
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         $this->verbose = (bool)$verbose;
     }
 
@@ -372,6 +386,10 @@ class TemplateService
      */
     public function matching($cc)
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         if (is_array($cc['all'])) {
             $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class, null, null, null, $this->absoluteRootLine);
             $matchObj->setRootline((array)($cc['rootLine'] ?? []));
@@ -395,6 +413,10 @@ class TemplateService
      */
     public function start($theRootLine)
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         $cc = [];
         if (is_array($theRootLine)) {
             $constantsData = [];
@@ -478,6 +500,10 @@ class TemplateService
      */
     public function runThroughTemplates($theRootLine, $start_template_uid = 0)
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         $this->constants = [];
         $this->config = [];
         $this->rowSum = [];
@@ -555,6 +581,10 @@ class TemplateService
      */
     public function processTemplate($row, $idList, $pid, $templateID = '', $templateParent = '', $includePath = '')
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         // Adding basic template record information to rowSum array
         $this->rowSum[] = [$row['uid'] ?? null, $row['title'] ?? null, $row['tstamp'] ?? null];
         // Processing "Clear"-flags
@@ -850,6 +880,10 @@ class TemplateService
      */
     public function generateConfig()
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         // Add default TS for all code types
         $this->addDefaultTypoScript();
 
@@ -1037,6 +1071,10 @@ class TemplateService
      */
     public function getRootlineLevel($list)
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         $idx = 0;
         foreach ($this->rootLine as $page) {
             if (GeneralUtility::inList($list, $page['uid'])) {
@@ -1054,6 +1092,10 @@ class TemplateService
      */
     public function getRootId(): int
     {
+        if (!self::$deprecationLogged) {
+            trigger_error(__CLASS__ . ' has been marked as deprecated in TYPO3 v12 and will be removed in v13.', E_USER_DEPRECATED);
+            self::$deprecationLogged = true;
+        }
         return (int)$this->rootId;
     }
 
diff --git a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
index 0ac8b458db24..c743f4e32b41 100644
--- a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
+++ b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
@@ -1230,7 +1230,7 @@ tt_content.' . $key . $suffix . ' {
         if ($afterStaticUid) {
             // If 'defaultContentRendering' is targeted (formerly static uid 43),
             // the content is added after TypoScript of type contentRendering, e.g. fluid_styled_content, see
-            // EXT:core/Classes/TypoScript/TemplateService.php for more information on how the code is parsed.
+            // EXT:core/Classes/TypoScript/IncludeTree/TreeBuilder.php for more information on how the code is parsed.
             if ($afterStaticUid === 'defaultContentRendering' || $afterStaticUid == 43) {
                 $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type . '.']['defaultContentRendering'] ??= '';
                 $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type . '.']['defaultContentRendering'] .= $content;
diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php
index 6db2bf6208df..d835d61f6126 100644
--- a/typo3/sysext/core/Configuration/DefaultConfiguration.php
+++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php
@@ -1384,7 +1384,7 @@ return [
         'additionalCanonicalizedUrlParameters' => [],
         'workspacePreviewLogoutTemplate' => '',
         'versionNumberInFilename' => 'querystring',
-        'contentRenderingTemplates' => [], // Array to define the TypoScript parts that define the main content rendering. Extensions like "fluid_styled_content" provide content rendering templates. Other extensions like "felogin" or "indexed search" extend these templates and their TypoScript parts are added directly after the content templates. See EXT:fluid_styled_content/ext_localconf.php and EXT:frontend/Classes/TypoScript/TemplateService.php
+        'contentRenderingTemplates' => [], // Array to define the TypoScript parts that define the main content rendering. Extensions like "fluid_styled_content" provide content rendering templates. Other extensions like "felogin" or "indexed search" extend these templates and their TypoScript parts are added directly after the content templates.
         'typolinkBuilder' => [  // Matches the LinkService implementations for generating URL, link text via typolink
             'page' => \TYPO3\CMS\Frontend\Typolink\PageLinkBuilder::class,
             'file' => \TYPO3\CMS\Frontend\Typolink\FileOrFolderLinkBuilder::class,
diff --git a/typo3/sysext/core/Documentation/Changelog/12.1/Deprecation-99020-DeprecateTypoScriptTemplateService.rst b/typo3/sysext/core/Documentation/Changelog/12.1/Deprecation-99020-DeprecateTypoScriptTemplateService.rst
new file mode 100644
index 000000000000..1bb16d4f85f4
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/12.1/Deprecation-99020-DeprecateTypoScriptTemplateService.rst
@@ -0,0 +1,49 @@
+.. include:: /Includes.rst.txt
+
+.. _deprecation-99020-1667911024:
+
+==========================================================
+Deprecation: #99020 - Deprecate TypoScript/TemplateService
+==========================================================
+
+See :issue:`99020`
+
+Description
+===========
+
+Class :php:`TYPO3\CMS\Core\TypoScript\TemplateService` has been marked as deprecated
+in TYPO3 v12 and will be removed in v13. This class is sometimes indirectly accessed
+using :php:`TypoScriptFrontendController->tmpl` or :php:`$GLOBALS['TSFE']->tmpl`.
+
+
+Impact
+======
+
+Class :php:`TemplateService` is part of the old TypoScript parser and has been
+substituted with a new parser approach. Actively calling class methods will
+trigger a deprecation log level warning.
+
+
+Affected installations
+======================
+
+Instances with extensions directly using :php:`TemplateService` or indirectly
+using it by calling :php:`TypoScriptFrontendController->tmpl` or
+:php:`$GLOBALS['TSFE']->tmpl` are affected.
+
+
+Migration
+=========
+
+Class :php:`TemplateService` is typically called in TYPO3 Frontend scope. Extensions
+should avoid using :php:`TypoScriptFrontendController->tmpl` and :php:`$GLOBALS['TSFE']->tmpl`
+methods and properties. They can retrieve TypoScript from the PSR-7 Request instead
+using the attribute :php:`frontend.typoscript`. As example, the full Frontend TypoScript
+can be retrieved like this:
+
+.. code-block:: php
+
+    $fullTypoScript = $request()->getAttribute('frontend.typoscript')->getSetupArray();
+
+
+.. index:: PHP-API, FullyScanned, ext:core
diff --git a/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Fixtures/ext_typoscript_setup.typoscript b/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Fixtures/ext_typoscript_setup.typoscript
new file mode 100644
index 000000000000..b843d96cb232
--- /dev/null
+++ b/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Fixtures/ext_typoscript_setup.typoscript
@@ -0,0 +1 @@
+test.Core.TypoScript = 1
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Unit/TypoScript/TemplateServiceTest.php b/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/TemplateServiceTest.php
similarity index 98%
rename from typo3/sysext/core/Tests/Unit/TypoScript/TemplateServiceTest.php
rename to typo3/sysext/core/Tests/UnitDeprecated/TypoScript/TemplateServiceTest.php
index ec5abe8b0ff5..fa2e771fd5c9 100644
--- a/typo3/sysext/core/Tests/Unit/TypoScript/TemplateServiceTest.php
+++ b/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/TemplateServiceTest.php
@@ -15,7 +15,7 @@ declare(strict_types=1);
  * The TYPO3 project - inspiring people to share!
  */
 
-namespace TYPO3\CMS\Core\Tests\Unit\TypoScript;
+namespace TYPO3\CMS\Core\Tests\UnitDeprecated\TypoScript;
 
 use PHPUnit\Framework\MockObject\MockObject;
 use TYPO3\CMS\Core\Context\Context;
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index 6adc6e91af11..bf16b0bd4de0 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -1431,7 +1431,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface
 
                 // Create top-level setup AST 'types' node from all top-level PAGE objects.
                 // This is essentially a preparation for type-lookup below and should vanish later.
-                // Previously, TemplateService->generateConfig() did that.
                 $typesNode = new ChildNode('types');
                 $gotTypeNumZero = false;
                 foreach ($setupAst->getNextChild() as $setupChild) {
diff --git a/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php b/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
index 5442934eecc7..215de7bcf22d 100644
--- a/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
+++ b/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
@@ -572,8 +572,6 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
      * 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
      */
@@ -637,7 +635,6 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
 
     /**
      * 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.
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
index 1e345ffbcc93..64d85dc2d751 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
@@ -2202,4 +2202,10 @@ return [
             'Deprecation-98996-DoctrineDBALBackendWorkspaceRestrictionAndFrontendWorkspaceRestriction.rst',
         ],
     ],
+    'TYPO3\CMS\Core\TypoScript\TemplateService' => [
+        'restFiles' => [
+            'Deprecation-99020-DeprecateTypoScriptTemplateService.rst',
+            'Breaking-97816-NewTypoScriptParserInFrontend.rst',
+        ],
+    ],
 ];
diff --git a/typo3/sysext/t3editor/Resources/Private/tsref.xml b/typo3/sysext/t3editor/Resources/Private/tsref.xml
index 31d2214f551f..c5bd4876fa63 100644
--- a/typo3/sysext/t3editor/Resources/Private/tsref.xml
+++ b/typo3/sysext/t3editor/Resources/Private/tsref.xml
@@ -205,7 +205,7 @@ This will by default add "&MP=2-207" to all links pointing to pages 36,37 and 48
 		<property name="MP_mapRootPoints" type="string">
 			<description><![CDATA[list of PIDs/string
       Defines a list of ID numbers from which the MP-vars are automatically calculated for the branch.
-The result is used just like MP_defaults are used to find MP-vars if none has been specified prior to the call to \TYPO3\CMS\Core\TypoScript\TemplateService::linkData().
+The result is used just like MP_defaults are used to find MP-vars if none has been specified.
 You can specify "root" as a special keyword in the list of IDs and that will create a map-tree for the whole site (but this may be VERY processing intensive if there are many pages!).
 The order of IDs specified may have a significance; Any ID in a branch which is processed already (by a previous ID root point) will not be processed again.]]></description>
 			<default><![CDATA[
@@ -2488,7 +2488,7 @@ Basically this shows that
 
 - the fields "header_layout", "bodytext" and "image" are mapped to non-existing fields in the page-record
 
-- a new field, "sectionIndex_uid" is introduced in the page-record which is detected by the function \TYPO3\CMS\Core\TypoScript\TemplateService->linkData(). If this field is present in a pagerecord, the linkData()-function will prepend a hash-mark and the number of the field.
+- a new field, "sectionIndex_uid" is introduced in the page-record. If this field is present in a page record, the linkData()-function will prepend a hash-mark and the number of the field.
 
 NOTE:
 
-- 
GitLab