Skip to content

Commit

Permalink
[TASK] Refine site set default TypoScript handling
Browse files Browse the repository at this point in the history
Treat site sets (#103439) as a default content rendering template,
in order to load Extbase plugin registrations prior to site sets.

Also add a possibility to opt out from being loaded globally in
site sets in ExtensionManagementUtility::addTypoScriptSetup
and ExtensionManagementUtility::addTypoScriptConstants in order
to reduce global TypoScript in upcoming commits (#103556).

Resolves: #103580
Related: #103439
Related: #103556
Releases: main
Change-Id: Ib9297c775d89f1689410f83e83955d6be829d2e6
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83722
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Benjamin Kott <benjamin.kott@outlook.com>
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Benjamin Kott <benjamin.kott@outlook.com>
  • Loading branch information
bnf committed Apr 11, 2024
1 parent 49963b3 commit 335c59d
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 23 deletions.
Expand Up @@ -86,6 +86,8 @@ final class SysTemplateTreeBuilder
private TokenizerInterface $tokenizer;
private ?PhpFrontend $cache = null;

private bool $enableStaticMagicIncludes = false;

public function __construct(
private readonly ConnectionPool $connectionPool,
private readonly PackageManager $packageManager,
Expand Down Expand Up @@ -116,6 +118,7 @@ public function getTreeBySysTemplateRowsAndSite(

$siteIsTypoScriptRoot = $site instanceof Site ? $site->isTypoScriptRoot() : false;
if ($siteIsTypoScriptRoot) {
$this->enableStaticMagicIncludes = false;
$cacheIdentifier = 'site-template-' . $this->type . '-' . $site->getIdentifier();
$includeNode = $this->cache?->require($cacheIdentifier) ?: null;
$includeNode ??= $this->createSiteTemplateInclude($site, $cacheIdentifier);
Expand All @@ -126,6 +129,7 @@ public function getTreeBySysTemplateRowsAndSite(
return $rootNode;
}

$this->enableStaticMagicIncludes = true;
// Convenience code: Usually, at least one sys_template records needs to have 'clear' set. This resets
// the AST and triggers inclusion of "globals" TypoScript. When integrators missed to set the clear flags,
// important globals TypoScript is not loaded, leading to pretty hard to find issues in Frontend
Expand Down Expand Up @@ -189,7 +193,8 @@ private function createSiteTemplateInclude(
$includeNode->setRoot(true);
$includeNode->setClear(true);

$this->addDefaultTypoScriptFromGlobals($includeNode);
$this->addScopedStaticsFromGlobals($includeNode, 'siteSets');
$this->addContentRenderingFromGlobals($includeNode, 'TYPO3_CONF_VARS defaultContentRendering');

$sets = $this->setRegistry->getSets(...$site->getSets());
if (count($sets) > 0) {
Expand All @@ -198,7 +203,6 @@ private function createSiteTemplateInclude(
$includeSetInclude->setPath('site:' . $site->getIdentifier() . '/');
foreach ($sets as $set) {
$this->handleSetInclude($includeSetInclude, rtrim($set->typoscript, '/') . '/', 'set:' . $set->name);
$this->addStaticMagicFromGlobals($includeSetInclude, 'set:' . $set->name);
}
$includeNode->addChild($includeSetInclude);
}
Expand All @@ -211,7 +215,7 @@ private function createSiteTemplateInclude(
$content = $this->type === 'constants' ? $siteTypoScript?->constants : $siteTypoScript?->setup;
if ($content !== null) {
$includeNode->setLineStream($this->tokenizer->tokenize($content));
$this->treeFromTokenStreamBuilder->buildTree($includeNode, $this->type, $this->tokenizer);
$this->treeFromTokenStreamBuilder->buildTree($includeNode, $this->type, $this->tokenizer, false);
}

$includeNode->setName(sprintf(
Expand Down Expand Up @@ -254,7 +258,7 @@ private function handleSetInclude(IncludeInterface $parentNode, string $path, st
$fileNode->setName($label . ':' . $this->type . '.typoscript');
$fileNode->setPath($fileName);
$fileNode->setLineStream($this->tokenizer->tokenize($fileContent));
$this->treeFromTokenStreamBuilder->buildTree($fileNode, $this->type, $this->tokenizer);
$this->treeFromTokenStreamBuilder->buildTree($fileNode, $this->type, $this->tokenizer, false);
$parentNode->addChild($fileNode);
}
}
Expand Down Expand Up @@ -441,8 +445,10 @@ private function handleSingleIncludeStaticFile(IncludeInterface $parentNode, $in
}
}

$extensionKeyWithoutUnderscores = str_replace('_', '', $extensionKey);
$this->addStaticMagicFromGlobals($parentNode, $extensionKeyWithoutUnderscores . '/' . $pathSegmentWithAppendedSlash);
if ($this->enableStaticMagicIncludes) {
$extensionKeyWithoutUnderscores = str_replace('_', '', $extensionKey);
$this->addStaticMagicFromGlobals($parentNode, $extensionKeyWithoutUnderscores . '/' . $pathSegmentWithAppendedSlash);
}
}

/**
Expand Down Expand Up @@ -534,11 +540,7 @@ private function addDefaultTypoScriptConstantsFromSite(IncludeInterface $parentC
$parentConstantNode->addChild($node);
}

/**
* A rather weird lookup in $GLOBALS['TYPO3_CONF_VARS']['FE'] for magic includes.
* See ExtensionManagementUtility::addTypoScript() for more details on this.
*/
private function addStaticMagicFromGlobals(IncludeInterface $parentNode, string $identifier): void
private function addScopedStaticsFromGlobals(IncludeInterface $parentNode, string $identifier): void
{
// defaultTypoScript_constants.' or defaultTypoScript_setup.'
$source = $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $this->type . '.'][$identifier] ?? null;
Expand All @@ -549,16 +551,30 @@ private function addStaticMagicFromGlobals(IncludeInterface $parentNode, string
$this->treeFromTokenStreamBuilder->buildTree($node, $this->type, $this->tokenizer);
$parentNode->addChild($node);
}
}

private function addContentRenderingFromGlobals(IncludeInterface $parentNode, string $name): void
{
$source = $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $this->type . '.']['defaultContentRendering'] ?? null;
if (!empty($source)) {
$node = new DefaultTypoScriptMagicKeyInclude();
$node->setName($name);
$node->setLineStream($this->tokenizer->tokenize($source));
$this->treeFromTokenStreamBuilder->buildTree($node, $this->type, $this->tokenizer);
$parentNode->addChild($node);
}
}

/**
* A rather weird lookup in $GLOBALS['TYPO3_CONF_VARS']['FE'] for magic includes.
* See ExtensionManagementUtility::addTypoScript() for more details on this.
*/
private function addStaticMagicFromGlobals(IncludeInterface $parentNode, string $identifier): void
{
$this->addScopedStaticsFromGlobals($parentNode, $identifier);
// If this is a template of type "default content rendering", see if other extensions have added their TypoScript that should be included.
if (in_array($identifier, $GLOBALS['TYPO3_CONF_VARS']['FE']['contentRenderingTemplates'], true)) {
$source = $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $this->type . '.']['defaultContentRendering'] ?? null;
if (!empty($source)) {
$node = new DefaultTypoScriptMagicKeyInclude();
$node->setName('TYPO3_CONF_VARS defaultContentRendering ' . $this->type . ' for ' . $identifier);
$node->setLineStream($this->tokenizer->tokenize($source));
$this->treeFromTokenStreamBuilder->buildTree($node, $this->type, $this->tokenizer);
$parentNode->addChild($node);
}
$this->addContentRenderingFromGlobals($parentNode, 'TYPO3_CONF_VARS defaultContentRendering ' . $this->type . ' for ' . $identifier);
}
}

Expand Down
Expand Up @@ -59,6 +59,7 @@ final class TreeFromLineStreamBuilder
/** @var 'constants'|'setup'|'other' */
private string $type;
private TokenizerInterface $tokenizer;
private bool $enableMagicIncludes = false;

/**
* Using "@import" with wildcards, the file ending depends on the given type:
Expand All @@ -78,14 +79,15 @@ public function __construct(
private readonly FileNameValidator $fileNameValidator,
) {}

public function buildTree(IncludeInterface $node, string $type, TokenizerInterface $tokenizer): void
public function buildTree(IncludeInterface $node, string $type, TokenizerInterface $tokenizer, bool $enableMagicIncludes = true): void
{
if (!in_array($type, ['constants', 'setup', 'tsconfig', 'other'], true)) {
// Type "constants" and "setup" trigger the weird addStaticMagicFromGlobals() resolving, while "other" ignores it.
throw new \RuntimeException('type must be either "constants", "setup", "tsconfig" or "other"', 1652741356);
}
$this->type = $type;
$this->tokenizer = $tokenizer;
$this->enableMagicIncludes = $enableMagicIncludes;
$this->buildTreeInternal($node);
}

Expand Down Expand Up @@ -560,6 +562,10 @@ private function addStaticMagicFromGlobals(IncludeInterface $parentNode, string
return;
}
$globalsLookup = $extensionKeyWithoutUnderscores . '/' . $pathSegmentWithAppendedSlash;

if (!$this->enableMagicIncludes) {
return;
}
// If this is a template of type "default content rendering", see if other extensions have added their TypoScript that should be included.
if (in_array($globalsLookup, $GLOBALS['TYPO3_CONF_VARS']['FE']['contentRenderingTemplates'], true)) {
$source = $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type . '.']['defaultContentRendering'] ?? null;
Expand Down
28 changes: 25 additions & 3 deletions typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
Expand Up @@ -1025,14 +1025,23 @@ public static function registerPageTSConfigFile(string $extKey, string $filePath
* FOR USE IN ext_localconf.php FILES
*
* @param string $content TypoScript Setup string
* @param bool $includeInSiteSets
*/
public static function addTypoScriptSetup(string $content): void
public static function addTypoScriptSetup(string $content, bool $includeInSiteSets = true): void
{
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'] ??= '';
if (!empty($GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'])) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'] .= LF;
}
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'] .= $content;

if ($includeInSiteSets) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['siteSets'] ??= '';
if (!empty($GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['siteSets'])) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['siteSets'] .= LF;
}
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['siteSets'] .= $content;
}
}

/**
Expand All @@ -1041,14 +1050,22 @@ public static function addTypoScriptSetup(string $content): void
* FOR USE IN ext_localconf.php FILES
*
* @param string $content TypoScript Constants string
* @param bool $includeInSiteSets
*/
public static function addTypoScriptConstants(string $content): void
public static function addTypoScriptConstants(string $content, bool $includeInSiteSets = true): void
{
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants'] ??= '';
if (!empty($GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants'])) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants'] .= LF;
}
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants'] .= $content;
if ($includeInSiteSets) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['siteSets'] ??= '';
if (!empty($GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['siteSets'])) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['siteSets'] .= LF;
}
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['siteSets'] .= $content;
}
}

/**
Expand All @@ -1068,7 +1085,7 @@ public static function addTypoScriptConstants(string $content): void
* @param int|string $afterStaticUid string pointing to the "key" of a static_file template ([reduced extension_key]/[local path]). The points is that the TypoScript you add is included only IF that static template is included (and in that case, right after). So effectively the TypoScript you set can specifically overrule settings from those static templates.
* @throws \InvalidArgumentException
*/
public static function addTypoScript(string $key, string $type, string $content, int|string $afterStaticUid = 0): void
public static function addTypoScript(string $key, string $type, string $content, int|string $afterStaticUid = 0, bool $includeInSiteSets = true): void
{
if ($type !== 'setup' && $type !== 'constants') {
throw new \InvalidArgumentException('Argument $type must be set to either "setup" or "constants" when calling addTypoScript from extension "' . $key . '"', 1507321200);
Expand All @@ -1095,6 +1112,11 @@ public static function addTypoScript(string $key, string $type, string $content,
} else {
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type] ??= '';
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type] .= $content;
if ($includeInSiteSets) {
// 'siteSets' is an @internal identifier
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type . '.']['siteSets'] ??= '';
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $type . '.']['siteSets'] .= $content;
}
}
}

Expand Down

0 comments on commit 335c59d

Please sign in to comment.