diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-94957-TypoScriptFrontendController-cObjectDepthCounter.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-94957-TypoScriptFrontendController-cObjectDepthCounter.rst new file mode 100644 index 0000000000000000000000000000000000000000..29b5abe492bbd04d1d391bac4942b77343bf4fe6 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-94957-TypoScriptFrontendController-cObjectDepthCounter.rst @@ -0,0 +1,42 @@ +.. include:: ../../Includes.txt + +======================================================================= +Deprecation: #94957 - TypoScriptFrontendController->cObjectDepthCounter +======================================================================= + +See :issue:`94957` + +Description +=========== + +The :php:`TypoScriptFrontendController` contains a property to prevent endless +recursion of content objects during frontend rendering. With TypoScript +becoming less complex, this check becomes obsolete. To reduce dependencies +between :php:`TypoScriptFrontendController` and :php:`ContentObjectRenderer`, +the handling has been removed and property :php:`TypoScriptFrontendController->cObjectDepthCounter` +has bee marked as deprecated. + + +Impact +====== + +If a TypoScript setup somehow manages to create a recursion, PHP will now stop +with a fatal PHP nesting level error at some point, instead of TYPO3 frontend +rendering silently stopping. + + +Affected Installations +====================== + +Instances using property :php:`TypoScriptFrontendController->cObjectDepthCounter` +are affected. That property has been handled mostly internally, this case is unlikely. +The extension scanner will find usages with a weak match. + + +Migration +========= + +Drop usages of property :php:`TypoScriptFrontendController->cObjectDepthCounter`, +it is unused within TYPO3 v11. + +.. index:: Frontend, PHP-API, FullyScanned, ext:frontend diff --git a/typo3/sysext/extbase/Classes/Utility/FrontendSimulatorUtility.php b/typo3/sysext/extbase/Classes/Utility/FrontendSimulatorUtility.php index 359db6bc8ee319a0c569b2b38719b902a7c8be7f..cf77bc543d1e75ea30c98f773f949959849fdbd5 100644 --- a/typo3/sysext/extbase/Classes/Utility/FrontendSimulatorUtility.php +++ b/typo3/sysext/extbase/Classes/Utility/FrontendSimulatorUtility.php @@ -34,8 +34,7 @@ class FrontendSimulatorUtility protected static $tsfeBackup; /** - * Sets the $TSFE->cObjectDepthCounter in Backend mode - * This somewhat hacky work around is currently needed because the cObjGetSingle() function of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on this setting + * \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle() relies on $GLOBALS['TSFE'] * * @param ContentObjectRenderer|null $cObj */ @@ -43,7 +42,6 @@ class FrontendSimulatorUtility { self::$tsfeBackup = $GLOBALS['TSFE'] ?? null; $GLOBALS['TSFE'] = new \stdClass(); - $GLOBALS['TSFE']->cObjectDepthCounter = 100; $GLOBALS['TSFE']->cObj = $cObj ?? GeneralUtility::makeInstance(ContentObjectRenderer::class); } diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php index cb65502758e2b04b2ff16560d75e869a4218eef1..aa108c5f8dae5954252e581a577d9939f307e428 100644 --- a/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php +++ b/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php @@ -237,15 +237,13 @@ class CObjectViewHelper extends AbstractViewHelper } /** - * Sets the $TSFE->cObjectDepthCounter in Backend mode - * This somewhat hacky work around is currently needed because the cObjGetSingle() function of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on this setting + * \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle() relies on $GLOBALS['TSFE'] */ protected static function simulateFrontendEnvironment() { static::$tsfeBackup = $GLOBALS['TSFE'] ?? null; $GLOBALS['TSFE'] = new \stdClass(); $GLOBALS['TSFE']->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class); - $GLOBALS['TSFE']->cObjectDepthCounter = 100; } /** diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php index bb84104979cf36421e51023d6bf71ee67f7a17f9..7dd3b666bc064e75eaeadd57fee3f3f7bb05ff44 100644 --- a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php +++ b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php @@ -706,38 +706,32 @@ class ContentObjectRenderer implements LoggerAwareInterface public function cObjGetSingle($name, $conf, $TSkey = '__') { $content = ''; - // Checking that the function is not called eternally. This is done by interrupting at a depth of 100 - $this->getTypoScriptFrontendController()->cObjectDepthCounter--; - if ($this->getTypoScriptFrontendController()->cObjectDepthCounter > 0) { - $timeTracker = $this->getTimeTracker(); - $name = trim($name); - if ($timeTracker->LR) { - $timeTracker->push($TSkey, $name); - } - // Checking if the COBJ is a reference to another object. (eg. name of 'some.object =< styles.something') - if (isset($name[0]) && $name[0] === '<') { - $key = trim(substr($name, 1)); - $cF = GeneralUtility::makeInstance(TypoScriptParser::class); - // $name and $conf is loaded with the referenced values. - $confOverride = is_array($conf) ? $conf : []; - [$name, $conf] = $cF->getVal($key, $this->getTypoScriptFrontendController()->tmpl->setup); - $conf = array_replace_recursive(is_array($conf) ? $conf : [], $confOverride); - // Getting the cObject - $timeTracker->incStackPointer(); - $content .= $this->cObjGetSingle($name, $conf, $key); - $timeTracker->decStackPointer(); - } else { - $contentObject = $this->getContentObject($name); - if ($contentObject) { - $content .= $this->render($contentObject, $conf); - } - } - if ($timeTracker->LR) { - $timeTracker->pull($content); + $timeTracker = $this->getTimeTracker(); + $name = trim($name); + if ($timeTracker->LR) { + $timeTracker->push($TSkey, $name); + } + // Checking if the COBJ is a reference to another object. (eg. name of 'some.object =< styles.something') + if (isset($name[0]) && $name[0] === '<') { + $key = trim(substr($name, 1)); + $cF = GeneralUtility::makeInstance(TypoScriptParser::class); + // $name and $conf is loaded with the referenced values. + $confOverride = is_array($conf) ? $conf : []; + [$name, $conf] = $cF->getVal($key, $this->getTypoScriptFrontendController()->tmpl->setup); + $conf = array_replace_recursive(is_array($conf) ? $conf : [], $confOverride); + // Getting the cObject + $timeTracker->incStackPointer(); + $content .= $this->cObjGetSingle($name, $conf, $key); + $timeTracker->decStackPointer(); + } else { + $contentObject = $this->getContentObject($name); + if ($contentObject) { + $content .= $this->render($contentObject, $conf); } } - // Increasing on exit... - $this->getTypoScriptFrontendController()->cObjectDepthCounter++; + if ($timeTracker->LR) { + $timeTracker->pull($content); + } return $content; } diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php index c39fd55dde9c4d659a872948346d3699a7d11f48..4f74261fc933a36c8ff6b768fd59485806acdd08 100644 --- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php +++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php @@ -438,6 +438,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface * Checking that the function is not called eternally. This is done by * interrupting at a depth of 50 * @var int + * @deprecated since v11, will be removed in v12. */ public $cObjectDepthCounter = 50; diff --git a/typo3/sysext/frontend/Tests/Unit/Plugin/AbstractPluginTest.php b/typo3/sysext/frontend/Tests/Unit/Plugin/AbstractPluginTest.php index d73752ec44bd7e0868ee86f021573848e5878554..e1bc7daa618c6c876e3190fc8cced07ea241c573 100644 --- a/typo3/sysext/frontend/Tests/Unit/Plugin/AbstractPluginTest.php +++ b/typo3/sysext/frontend/Tests/Unit/Plugin/AbstractPluginTest.php @@ -53,7 +53,6 @@ class AbstractPluginTest extends UnitTestCase parent::setUp(); $tsfe = $this->prophesize(TypoScriptFrontendController::class); - $tsfe->cObjectDepthCounter = 100; $tsfe->getLanguage(Argument::cetera())->willReturn( $this->createSiteWithDefaultLanguage()->getLanguageById(0) ); diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php index 34adf66b907e1b3550bcfc76d120216fcb9bea09..17ab1bb7152129eabcdff5fd68676684ab1a9c8f 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php @@ -870,4 +870,9 @@ return [ 'Deprecation-94958-ContentObjectRendererProperties.rst', ], ], + 'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->cObjectDepthCounter' => [ + 'restFiles' => [ + 'Deprecation-94957-TypoScriptFrontendController-cObjectDepthCounter.rst' + ], + ], ];