‪TYPO3CMS  ‪main
PageTsConfigFactory.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Container\ContainerInterface;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
35 
44 {
45  public function ‪__construct(
46  private readonly ContainerInterface $container,
47  private readonly ‪TokenizerInterface $tokenizer,
48  private readonly ‪TsConfigTreeBuilder $tsConfigTreeBuilder,
49  private readonly ‪PhpFrontend $cache,
50  ) {}
51 
52  public function ‪create(
53  array $fullRootLine,
54  ‪SiteInterface $site,
55  ?‪UserTsConfig $userTsConfig = null
56  ): ‪PageTsConfig {
57  $pagesTsConfigTree = $this->tsConfigTreeBuilder->getPagesTsConfigTree($fullRootLine, $this->tokenizer, $this->cache);
58 
59  // Overloading with user TSconfig if hand over
60  if ($userTsConfig !== null) {
61  $userTsConfigAst = $userTsConfig->getUserTsConfigTree();
62  $userTsConfigPageOverrides = '';
63  // @todo: This is ugly and expensive. There should be a better way to do this. Similar in BE page TSconfig controllers.
64  $userTsConfigFlat = $userTsConfigAst->flatten();
65  foreach ($userTsConfigFlat as $userTsConfigIdentifier => $userTsConfigValue) {
66  if (str_starts_with($userTsConfigIdentifier, 'page.')) {
67  $userTsConfigPageOverrides .= substr($userTsConfigIdentifier, 5) . ' = ' . $userTsConfigValue . chr(10);
68  }
69  }
70  if (!empty($userTsConfigPageOverrides)) {
71  $includeNode = new ‪TsConfigInclude();
72  $includeNode->setName('pageTsConfig-overrides-by-userTsConfig');
73  $includeNode->setLineStream($this->tokenizer->tokenize($userTsConfigPageOverrides));
74  $pagesTsConfigTree->addChild($includeNode);
75  }
76  }
77 
78  // Prepare site constants to be substituted
79  $includeTreeTraverserConditionVerdictAware = new ‪ConditionVerdictAwareIncludeTreeTraverser();
80  $siteSettingsFlat = [];
81  if ($site instanceof ‪Site) {
82  $siteSettings = $site->getSettings();
83  if (!$siteSettings->isEmpty()) {
84  $siteSettingsCacheIdentifier = 'site-settings-flat-' . hash('xxh3', json_encode($siteSettings, JSON_THROW_ON_ERROR));
85  $siteSettingsCacheArray = $this->cache->require($siteSettingsCacheIdentifier);
86  if (isset($siteSettingsCacheArray['flatConstants'])) {
87  $siteSettingsFlat = $siteSettingsCacheArray['flatConstants'];
88  } else {
89  $siteConstants = '';
90  $siteSettings = $siteSettings->getAllFlat();
91  foreach ($siteSettings as $nodeIdentifier => $value) {
92  $siteConstants .= $nodeIdentifier . ' = ' . $value . LF;
93  }
94  $siteSettingsNode = new ‪SiteInclude();
95  $siteSettingsNode->setName('Site constants settings of site "' . $site->‪getIdentifier() . '"');
96  $siteSettingsNode->setLineStream($this->tokenizer->tokenize($siteConstants));
97  $siteSettingsTreeRoot = new ‪RootInclude();
98  $siteSettingsTreeRoot->addChild($siteSettingsNode);
99  $astBuilderVisitor = $this->container->get(IncludeTreeAstBuilderVisitor::class);
100  $includeTreeTraverserConditionVerdictAware->traverse($siteSettingsTreeRoot, [$astBuilderVisitor]);
101  $siteSettingsFlat = $astBuilderVisitor->getAst()->flatten();
102  $this->cache->set($siteSettingsCacheIdentifier, 'return unserialize(\'' . addcslashes(serialize(['flatConstants' => $siteSettingsFlat]), '\'\\') . '\');');
103  }
104  }
105  }
106 
107  // Create AST with constants from site and conditions
108  $includeTreeTraverserConditionVerdictAwareVisitors = [];
109  if (!empty($siteSettingsFlat)) {
110  $setupConditionConstantSubstitutionVisitor = new ‪IncludeTreeSetupConditionConstantSubstitutionVisitor();
111  $setupConditionConstantSubstitutionVisitor->setFlattenedConstants($siteSettingsFlat);
112  $includeTreeTraverserConditionVerdictAwareVisitors[] = $setupConditionConstantSubstitutionVisitor;
113  }
114  $lastPageFullRecord = [];
115  $pageId = 0;
116  if (!empty($fullRootLine)) {
117  $lastPage = $fullRootLine[array_key_last($fullRootLine)];
118  $pageId = $lastPage['uid'];
119  $lastPageFullRecord = BackendUtility::getRecord('pages', $pageId) ?: [];
120  }
121  $conditionMatcherVariables = [
122  'fullRootLine' => $fullRootLine,
123  'site' => $site,
124  // @todo We're using the full page row here to provide all necessary fields (e.g. "backend_layout"),
125  // which are currently not included in the rows, RootlineUtility provides by default. We might
126  // want to switch to $fullRootLine[array_key_last($fullRootLine)] as soon as it contains all fields.
127  'page' => $lastPageFullRecord,
128  'pageId' => $pageId,
129  ];
130  $conditionMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
131  $conditionMatcherVisitor->initializeExpressionMatcherWithVariables($conditionMatcherVariables);
132  $includeTreeTraverserConditionVerdictAwareVisitors[] = $conditionMatcherVisitor;
133  $astBuilderVisitor = $this->container->get(IncludeTreeAstBuilderVisitor::class);
134  $astBuilderVisitor->setFlatConstants($siteSettingsFlat);
135  $includeTreeTraverserConditionVerdictAwareVisitors[] = $astBuilderVisitor;
136  $includeTreeTraverserConditionVerdictAware->traverse($pagesTsConfigTree, $includeTreeTraverserConditionVerdictAwareVisitors);
137 
138  return new ‪PageTsConfig($astBuilderVisitor->getAst());
139  }
140 }
‪TYPO3\CMS\Core\Site\Entity\SiteInterface
Definition: SiteInterface.php:26
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSetupConditionConstantSubstitutionVisitor
Definition: IncludeTreeSetupConditionConstantSubstitutionVisitor.php:36
‪TYPO3\CMS\Core\TypoScript\UserTsConfig
Definition: UserTsConfig.php:28
‪TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
Definition: PhpFrontend.php:25
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeAstBuilderVisitor
Definition: IncludeTreeAstBuilderVisitor.php:39
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\TypoScript\PageTsConfigFactory\__construct
‪__construct(private readonly ContainerInterface $container, private readonly TokenizerInterface $tokenizer, private readonly TsConfigTreeBuilder $tsConfigTreeBuilder, private readonly PhpFrontend $cache,)
Definition: PageTsConfigFactory.php:45
‪TYPO3\CMS\Core\TypoScript
‪TYPO3\CMS\Core\TypoScript\PageTsConfig
Definition: PageTsConfig.php:28
‪TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\SiteInclude
Definition: SiteInclude.php:25
‪TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\TsConfigInclude
Definition: TsConfigInclude.php:25
‪TYPO3\CMS\Core\TypoScript\PageTsConfigFactory
Definition: PageTsConfigFactory.php:44
‪TYPO3\CMS\Core\TypoScript\PageTsConfigFactory\create
‪create(array $fullRootLine, SiteInterface $site, ?UserTsConfig $userTsConfig=null)
Definition: PageTsConfigFactory.php:52
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Traverser\ConditionVerdictAwareIncludeTreeTraverser
Definition: ConditionVerdictAwareIncludeTreeTraverser.php:38
‪TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\RootInclude
Definition: RootInclude.php:27
‪TYPO3\CMS\Core\TypoScript\Tokenizer\TokenizerInterface
Definition: TokenizerInterface.php:40
‪TYPO3\CMS\Core\Site\Entity\SiteInterface\getIdentifier
‪getIdentifier()
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\TypoScript\IncludeTree\TsConfigTreeBuilder
Definition: TsConfigTreeBuilder.php:44
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor
Definition: IncludeTreeConditionMatcherVisitor.php:44