From a55b2b8839467540b27b77644214fd7b66ac62f3 Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Sun, 12 Apr 2020 00:03:39 +0200
Subject: [PATCH] [TASK] Deprecate various hooks related to
 TypoScriptFrontendController

PSR-15 and Request/Response handling has been proven to be a
worthy replacement for most logic related for outputting content
in the TYPO3 Frontend.

In order to thin out TSFE in future TYPO3 versions, various hooks have
been deprecated as they can also be used with proper PSR-15 middlewares.

* $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing']
* $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting']
* $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace']
* $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']

The following methods are marked as deprecated as well:
* $TSFE->isOutputting()
* $TSFE->processContentForOutput()

Resolves: #91012
Releases: master
Change-Id: I455f110f7f3e774de9d8ccd4adfcbd1ed5538cec
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64118
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Josef Glatz <josefglatz@gmail.com>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Josef Glatz <josefglatz@gmail.com>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../Middleware/AdminPanelDataPersister.php    |  2 +-
 .../Classes/Middleware/AdminPanelRenderer.php |  2 +-
 ...sRelatedToTypoScriptFrontendController.rst | 66 ++++++++++++++++
 .../TypoScriptFrontendController.php          | 29 ++++++-
 .../frontend/Classes/Hooks/FrontendHooks.php  | 76 -------------------
 .../frontend/Classes/Http/RequestHandler.php  | 59 +++++++++++++-
 .../ContentLengthResponseHeader.php           |  2 +-
 typo3/sysext/frontend/ext_localconf.php       |  3 -
 .../Classes/Hook/TypoScriptFrontendHook.php   |  9 +--
 typo3/sysext/indexed_search/ext_localconf.php |  2 +-
 .../Php/ArrayDimensionMatcher.php             | 25 ++++++
 .../Php/MethodCallMatcher.php                 | 14 ++++
 .../Classes/Middleware/WorkspacePreview.php   |  2 +-
 13 files changed, 197 insertions(+), 94 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst
 delete mode 100644 typo3/sysext/frontend/Classes/Hooks/FrontendHooks.php

diff --git a/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelDataPersister.php b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelDataPersister.php
index 03eb2b32fbcc..d7623566086b 100644
--- a/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelDataPersister.php
+++ b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelDataPersister.php
@@ -45,7 +45,7 @@ class AdminPanelDataPersister implements MiddlewareInterface
         if (
             !($response instanceof NullResponse)
             && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController
-            && $GLOBALS['TSFE']->isOutputting()
+            && $GLOBALS['TSFE']->isOutputting(true)
             && StateUtility::isActivatedForUser()
             && StateUtility::isActivatedInTypoScript()
             && !StateUtility::isHiddenForUser()
diff --git a/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelRenderer.php b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelRenderer.php
index d2afba1f57db..dda2072129d6 100644
--- a/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelRenderer.php
+++ b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelRenderer.php
@@ -47,7 +47,7 @@ class AdminPanelRenderer implements MiddlewareInterface
         if (
             !($response instanceof NullResponse)
             && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController
-            && $GLOBALS['TSFE']->isOutputting()
+            && $GLOBALS['TSFE']->isOutputting(true)
             && StateUtility::isActivatedForUser()
             && StateUtility::isActivatedInTypoScript()
             && !StateUtility::isHiddenForUser()
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst
new file mode 100644
index 000000000000..2563279ba218
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst
@@ -0,0 +1,66 @@
+.. include:: ../../Includes.txt
+
+===========================================================================
+Deprecation: #91012 - Various hooks related to TypoScriptFrontendController
+===========================================================================
+
+See :issue:`91012`
+
+Description
+===========
+
+The following hooks related to TypoScriptFrontendController
+and frontend-rendering have been deprecated:
+
+* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing']`
+* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting']`
+* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace']`
+* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']`
+* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']`
+
+The following methods have been deprecated as well, as they only
+contain code relevant for executing the hooks:
+
+* :php:`TypoScriptFrontendController->isOutputting()`
+* :php:`TypoScriptFrontendController->processContentForOutput()`
+
+
+Impact
+======
+
+If third-party extensions are using the hooks, a PHP deprecation warning will be triggered when the hook is executed.
+
+Calling the two methods above will also trigger a deprecation warning.
+
+
+Affected Installations
+======================
+
+TYPO3 installations with custom extensions using the hooks or mentioned above, which is likely common if they haven't been using
+PSR-15 middlewares or other hooks instead.
+
+
+Migration
+=========
+
+The hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing']` should be replaced by the :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached']` hook to index pages. However, please note that `$TSFE->content` might contain UTF-8 content now, instead of content already converted to the defined character set related to `metaCharset` TypoScript property.
+
+Since TYPO3 v9, the emitter of HTTP responses is based on PSR-7, the hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting']` can be removed, as
+TYPO3 can be configured via PSR-15 middlewares to define whether
+page content should be emitted / rendered or not.
+
+The hook to dynamically replace content via
+ :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace']`
+is removed as it serves no purpose for TYPO3 Core anymore. If content should be dynamically modified, use a PSR-15 middleware instead.
+
+The hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']` is not needed as this can be built via a PSR-15 middleware instead, and
+all content is returned via the RequestHandler of TYPO3 Frontend.
+
+Extensions using hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']` should be converted to PSR-15 middlewares, as this allows to modify content and headers of a PSR-7 Response object.
+
+The method :php:`TypoScriptFrontendController->isOutputting()` is obsolete and can be removed in third-party code.
+
+The same applies to :php:`TypoScriptFrontendController->processContentForOutput()` which should only be used to trigger
+legacy hooks still applied in the system.
+
+.. index:: PHP-API, FullyScanned, ext:frontend
\ No newline at end of file
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index 407d2af48357..a8588d3016e7 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -2860,6 +2860,9 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         // to utf-8 so the content MUST be in metaCharset already!
         $this->content = $this->convOutputCharset($this->content);
         // Hook for indexing pages
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'])) {
+            trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_fe.php][pageIndexing] will be removed in TYPO3 v11.0. Use the contentPostProc-all hook and convert the content if the output charset does not match the internal format.', E_USER_DEPRECATED);
+        }
         foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'] ?? [] as $className) {
             GeneralUtility::makeInstance($className)->hook_indexContent($this);
         }
@@ -3169,10 +3172,18 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      * Determines if content should be outputted.
      * Outputting content is done only if no URL handler is active and no hook disables the output.
      *
+     * @param bool $isCoreCall if set to "true" no deprecation warning will be triggered, because TYPO3 keeps calling this method to keep backwards-compatibility
      * @return bool Returns TRUE if no redirect URL is set and no hook disables the output.
+     * @deprecated will be removed in TYPO3 v11.0. Do not call this method anymore.
      */
-    public function isOutputting()
+    public function isOutputting(bool $isCoreCall = false)
     {
+        if ($isCoreCall !== true) {
+            trigger_error('TypoScriptFrontendController->isOutputting will be removed in TYPO3 v11.0, do not depend on this method anymore. Definition of outputting can be configured via PSR-15 middlewares.', E_USER_DEPRECATED);
+        }
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'])) {
+            trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_fe.php][isOutputting] will be removed in TYPO3 v11.0. This hook has various side-effects (as the method is called multiple times during one request) and the configuration if TYPO3 is outputting the content is handled via the Emitter / PSR-15 middlewares.', E_USER_DEPRECATED);
+        }
         // Initialize by status if there is a Redirect URL
         $enableOutput = true;
         // Call hook for possible disabling of output:
@@ -3188,15 +3199,24 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      *
      * This includes substituting the "username" comment.
      * Works on $this->content.
+     *
+     * @param bool $isCoreCall if set to "true" no deprecation warning will be triggered, because TYPO3 keeps calling this method to keep backwards-compatibility
+     * @deprecated this method will be removed in TYPO3 v11. Use a PSR-15 middleware for processing content.
      */
-    public function processContentForOutput()
+    public function processContentForOutput(bool $isCoreCall = false)
     {
+        if ($isCoreCall !== true) {
+            trigger_error('TypoScriptFrontendController->processContentForOutput will be removed in TYPO3 v11.0, do not depend on this method anymore. Definition of outputting can be configured via PSR-15 middlewares.', E_USER_DEPRECATED);
+        }
         // Make substitution of eg. username/uid in content only if cache-headers for client/proxy caching is NOT sent!
         if (!$this->isClientCachable) {
             // Substitute various tokens in content. This should happen only if the content is not cached by proxies or client browsers.
             $search = [];
             $replace = [];
             // Hook for supplying custom search/replace data
+            if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'])) {
+                trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_fe.php][tslib_fe-contentStrReplace] will be removed in TYPO3 v11.0. Use a custom PSR-15 middleware instead.', E_USER_DEPRECATED);
+            }
             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'] ?? [] as $_funcRef) {
                 $_params = [
                     'search' => &$search,
@@ -3208,6 +3228,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
                 $this->content = str_replace($search, $replace, $this->content);
             }
         }
+        // Hook for supplying custom search/replace data
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'])) {
+            trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_fe.php][contentPostProc-output] will be removed in TYPO3 v11.0. Use a custom PSR-15 middleware instead.', E_USER_DEPRECATED);
+        }
+
         // Hook for post-processing of page content before output:
         $_params = ['pObj' => &$this];
         foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'] ?? [] as $_funcRef) {
diff --git a/typo3/sysext/frontend/Classes/Hooks/FrontendHooks.php b/typo3/sysext/frontend/Classes/Hooks/FrontendHooks.php
deleted file mode 100644
index 2d49ad2fda03..000000000000
--- a/typo3/sysext/frontend/Classes/Hooks/FrontendHooks.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace TYPO3\CMS\Frontend\Hooks;
-
-/*
- * 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!
- */
-
-use TYPO3\CMS\Core\Localization\LanguageService;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
-
-/**
- * Uses frontend hooks to show preview information
- * @internal this is a concrete TYPO3 hook implementation and solely used for EXT:frontend and not part of TYPO3's Core API.
- */
-class FrontendHooks
-{
-    /**
-     * Include the preview block in case we're looking at a hidden page
-     * in the LIVE workspace
-     *
-     * @param array $params
-     * @param TypoScriptFrontendController $controller
-     */
-    public function displayPreviewInfoMessage($params, TypoScriptFrontendController $controller)
-    {
-        $isInPreviewMode = $controller->getContext()->hasAspect('frontend.preview')
-            && $controller->getContext()->getPropertyFromAspect('frontend.preview', 'isPreview');
-        if (!$isInPreviewMode || $controller->doWorkspacePreview() || ($controller->config['config']['disablePreviewNotification'] ?? false)) {
-            return;
-        }
-        if ($controller->config['config']['message_preview']) {
-            $message = $controller->config['config']['message_preview'];
-        } else {
-            $label = $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_tsfe.xlf:preview');
-            $styles = [];
-            $styles[] = 'position: fixed';
-            $styles[] = 'top: 15px';
-            $styles[] = 'right: 15px';
-            $styles[] = 'padding: 8px 18px';
-            $styles[] = 'background: #fff3cd';
-            $styles[] = 'border: 1px solid #ffeeba';
-            $styles[] = 'font-family: sans-serif';
-            $styles[] = 'font-size: 14px';
-            $styles[] = 'font-weight: bold';
-            $styles[] = 'color: #856404';
-            $styles[] = 'z-index: 20000';
-            $styles[] = 'user-select: none';
-            $styles[] = 'pointer-events: none';
-            $styles[] = 'text-align: center';
-            $styles[] = 'border-radius: 2px';
-            $message = '<div id="typo3-preview-info" style="' . implode(';', $styles) . '">' . htmlspecialchars($label) . '</div>';
-        }
-        if (!empty($message)) {
-            $controller->content = str_ireplace('</body>', $message . '</body>', $controller->content);
-        }
-    }
-
-    /**
-     * @return LanguageService
-     */
-    protected function getLanguageService()
-    {
-        return $GLOBALS['LANG'];
-    }
-}
diff --git a/typo3/sysext/frontend/Classes/Http/RequestHandler.php b/typo3/sysext/frontend/Classes/Http/RequestHandler.php
index 92b883c88baf..83e50bb700bc 100644
--- a/typo3/sysext/frontend/Classes/Http/RequestHandler.php
+++ b/typo3/sysext/frontend/Classes/Http/RequestHandler.php
@@ -24,6 +24,7 @@ use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Http\NullResponse;
 use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\Information\Typo3Information;
+use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Page\AssetCollector;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
@@ -152,19 +153,25 @@ class RequestHandler implements RequestHandlerInterface
         $response = new Response();
 
         // Output content
-        $isOutputting = $controller->isOutputting();
+        // The if() condition can be removed in TYPO3 v11, which means that TYPO3 will not return a NullResponse
+        // by default anymore, which it hasn't done without any extensions anyway already.
+        $isOutputting = $controller->isOutputting(true);
         if ($isOutputting) {
             $this->timeTracker->push('Print Content');
             $response = $controller->applyHttpHeadersToResponse($response);
-            $controller->processContentForOutput();
+            $controller->processContentForOutput(true);
             $this->timeTracker->pull();
         }
 
         // Hook for "end-of-frontend"
         $_params = ['pObj' => &$controller];
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'])) {
+            trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_fe.php][hook_eofe] will be removed in TYPO3 v11.0. The same functionality can be achieved by using a PSR-15 middleware.', E_USER_DEPRECATED);
+        }
         foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'] ?? [] as $_funcRef) {
             GeneralUtility::callUserFunction($_funcRef, $_params, $controller);
         }
+        $this->displayPreviewInfoMessage($controller);
 
         if ($isOutputting) {
             $response->getBody()->write($controller->content);
@@ -1057,4 +1064,52 @@ class RequestHandler implements RequestHandlerInterface
             $controller->additionalHeaderData[] = implode(LF, $data);
         }
     }
+
+    /**
+     * Include the preview block in case we're looking at a hidden page in the LIVE workspace
+     *
+     * @param TypoScriptFrontendController $controller
+     * @internal this method might get moved to a PSR-15 middleware at some point
+     */
+    protected function displayPreviewInfoMessage(TypoScriptFrontendController $controller)
+    {
+        $isInPreviewMode = $controller->getContext()->hasAspect('frontend.preview')
+            && $controller->getContext()->getPropertyFromAspect('frontend.preview', 'isPreview');
+        if (!$isInPreviewMode || $controller->doWorkspacePreview() || ($controller->config['config']['disablePreviewNotification'] ?? false)) {
+            return;
+        }
+        if ($controller->config['config']['message_preview']) {
+            $message = $controller->config['config']['message_preview'];
+        } else {
+            $label = $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_tsfe.xlf:preview');
+            $styles = [];
+            $styles[] = 'position: fixed';
+            $styles[] = 'top: 15px';
+            $styles[] = 'right: 15px';
+            $styles[] = 'padding: 8px 18px';
+            $styles[] = 'background: #fff3cd';
+            $styles[] = 'border: 1px solid #ffeeba';
+            $styles[] = 'font-family: sans-serif';
+            $styles[] = 'font-size: 14px';
+            $styles[] = 'font-weight: bold';
+            $styles[] = 'color: #856404';
+            $styles[] = 'z-index: 20000';
+            $styles[] = 'user-select: none';
+            $styles[] = 'pointer-events: none';
+            $styles[] = 'text-align: center';
+            $styles[] = 'border-radius: 2px';
+            $message = '<div id="typo3-preview-info" style="' . implode(';', $styles) . '">' . htmlspecialchars($label) . '</div>';
+        }
+        if (!empty($message)) {
+            $controller->content = str_ireplace('</body>', $message . '</body>', $controller->content);
+        }
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService()
+    {
+        return $GLOBALS['LANG'];
+    }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/ContentLengthResponseHeader.php b/typo3/sysext/frontend/Classes/Middleware/ContentLengthResponseHeader.php
index c758beac8a8a..a5a92ace37f0 100644
--- a/typo3/sysext/frontend/Classes/Middleware/ContentLengthResponseHeader.php
+++ b/typo3/sysext/frontend/Classes/Middleware/ContentLengthResponseHeader.php
@@ -46,7 +46,7 @@ class ContentLengthResponseHeader implements MiddlewareInterface
         if (
             !($response instanceof NullResponse)
             && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController
-            && $GLOBALS['TSFE']->isOutputting()) {
+            && $GLOBALS['TSFE']->isOutputting(true)) {
             if (
                     (!isset($GLOBALS['TSFE']->config['config']['enableContentLengthHeader']) || $GLOBALS['TSFE']->config['config']['enableContentLengthHeader'])
                     && !$GLOBALS['TSFE']->isBackendUserLoggedIn() && !$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']
diff --git a/typo3/sysext/frontend/ext_localconf.php b/typo3/sysext/frontend/ext_localconf.php
index 2e07efb00156..32d241c2f947 100644
--- a/typo3/sysext/frontend/ext_localconf.php
+++ b/typo3/sysext/frontend/ext_localconf.php
@@ -70,9 +70,6 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['proc
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'][] = \TYPO3\CMS\Frontend\Hooks\TreelistCacheUpdateHooks::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'][] = \TYPO3\CMS\Frontend\Hooks\TreelistCacheUpdateHooks::class;
 
-// Register hook to show preview info
-$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']['preview-message'] = \TYPO3\CMS\Frontend\Hooks\FrontendHooks::class . '->displayPreviewInfoMessage';
-
 // Register for hooks to show preview of tt_content elements in page module
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['image'] =
     \TYPO3\CMS\Frontend\Hooks\PageLayoutView\ImagePreviewRenderer::class;
diff --git a/typo3/sysext/indexed_search/Classes/Hook/TypoScriptFrontendHook.php b/typo3/sysext/indexed_search/Classes/Hook/TypoScriptFrontendHook.php
index 8350b0cc9b3d..9d33234f6643 100644
--- a/typo3/sysext/indexed_search/Classes/Hook/TypoScriptFrontendHook.php
+++ b/typo3/sysext/indexed_search/Classes/Hook/TypoScriptFrontendHook.php
@@ -51,9 +51,10 @@ class TypoScriptFrontendHook
     /**
      * Trigger indexing of content, after evaluating if this page could / should be indexed.
      *
+     * @param array $parameters
      * @param TypoScriptFrontendController $tsfe
      */
-    public function hook_indexContent(TypoScriptFrontendController $tsfe)
+    public function indexPageContent(array $parameters, TypoScriptFrontendController $tsfe)
     {
         // Determine if page should be indexed, and if so, configure and initialize indexer
         if (!$tsfe->config['config']['index_enable']) {
@@ -75,10 +76,6 @@ class TypoScriptFrontendHook
             $timeTracker->setTSlogMessage('Index page? No, The "No Search" flag has been set in the page properties!');
             return;
         }
-        if ($tsfe->no_cache) {
-            $timeTracker->setTSlogMessage('Index page? No, Ordinary Frontend indexing during rendering is disabled.');
-            return;
-        }
         /** @var LanguageAspect $languageAspect */
         $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
         if ($languageAspect->getId() !== $languageAspect->getContentId()) {
@@ -127,7 +124,7 @@ class TypoScriptFrontendHook
             $configuration['rootline_uids'][$rlkey] = $rldat['uid'];
         }
         // Content of page
-        $configuration['content'] = $tsfe->content;
+        $configuration['content'] = $this->convOutputCharset($tsfe->content, $tsfe->metaCharset);
         // Content string (HTML of TYPO3 page)
         $configuration['indexedDocTitle'] = $this->convOutputCharset($tsfe->indexedDocTitle, $tsfe->metaCharset);
         // Alternative title for indexing
diff --git a/typo3/sysext/indexed_search/ext_localconf.php b/typo3/sysext/indexed_search/ext_localconf.php
index ccbd257d9e06..2fc3d6801095 100644
--- a/typo3/sysext/indexed_search/ext_localconf.php
+++ b/typo3/sysext/indexed_search/ext_localconf.php
@@ -10,7 +10,7 @@ defined('TYPO3_MODE') or die();
 );
 
 // Attach to hooks:
-$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'][] = \TYPO3\CMS\IndexedSearch\Hook\TypoScriptFrontendHook::class;
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached']['indexed_search'] = \TYPO3\CMS\IndexedSearch\Hook\TypoScriptFrontendHook::class . '->indexPageContent';
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache']['tx_indexedsearch'] = \TYPO3\CMS\IndexedSearch\Hook\TypoScriptFrontendHook::class . '->headerNoCache';
 // Register with "crawler" extension:
 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['procInstructions']['indexed_search'] = [
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ArrayDimensionMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ArrayDimensionMatcher.php
index 26c3acef6b4d..33461d9e588c 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ArrayDimensionMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ArrayDimensionMatcher.php
@@ -391,4 +391,29 @@ return [
             'Deprecation-90937-VariousHooksInContentObjectRenderer.rst',
         ],
     ],
+    '$GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][\'tslib/class.tslib_fe.php\'][\'pageIndexing\']' => [
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
+    '$GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][\'tslib/class.tslib_fe.php\'][\'isOutputting\']' => [
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
+    '$GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][\'tslib/class.tslib_fe.php\'][\'tslib_fe-contentStrReplace\']' => [
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
+    '$GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][\'tslib/class.tslib_fe.php\'][\'contentPostProc-output\']' => [
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
+    '$GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][\'tslib/class.tslib_fe.php\'][\'hook_eofe\']' => [
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
 ];
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
index db55f3650012..18432131fa2b 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
@@ -4483,4 +4483,18 @@ return [
             'Deprecation-90964-LanguageServiceFunctionalityAndInternalProperties.rst',
         ],
     ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->isOutputting' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->processContentForOutput' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-91012-VariousHooksRelatedToTypoScriptFrontendController.rst',
+        ],
+    ],
 ];
diff --git a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
index 206341069092..37bbad153311 100644
--- a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
+++ b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
@@ -119,7 +119,7 @@ class WorkspacePreview implements MiddlewareInterface
         }
 
         // Add an info box to the frontend content
-        if ($GLOBALS['TSFE']->doWorkspacePreview() && $GLOBALS['TSFE']->isOutputting()) {
+        if ($GLOBALS['TSFE']->doWorkspacePreview() && $GLOBALS['TSFE']->isOutputting(true)) {
             $previewInfo = $this->renderPreviewInfo($GLOBALS['TSFE'], $request->getAttribute('normalizedParams'));
             $body = $response->getBody();
             $body->rewind();
-- 
GitLab