‪TYPO3CMS  ‪main
IncludeTreeConditionMatcherVisitor.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\Log\LoggerAwareInterface;
21 use Psr\Log\LoggerAwareTrait;
22 use Symfony\Component\ExpressionLanguage\SyntaxError;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
32 
43 final class ‪IncludeTreeConditionMatcherVisitor implements ‪IncludeTreeVisitorInterface, LoggerAwareInterface
44 {
45  use LoggerAwareTrait;
46 
48  private array ‪$conditionList = [];
49 
50  public function ‪__construct(
51  private readonly ‪Context $context,
52  private readonly ‪PageLayoutResolver $pageLayoutResolver,
53  ) {}
54 
66  public function ‪initializeExpressionMatcherWithVariables(array $variables): void
67  {
68  $context = $this->context;
69  $enrichedVariables = [
70  'context' => $context,
71  ];
72  // Variables derived directly from context are set if context provides according aspects.
73  $frontendUserAspect = $this->context->getAspect('frontend.user');
74  if ($frontendUserAspect instanceof ‪UserAspect) {
75  $frontend = new \stdClass();
76  $frontend->user = new \stdClass();
77  $frontend->user->isLoggedIn = $frontendUserAspect->get('isLoggedIn');
78  $frontend->user->userId = $frontendUserAspect->get('id');
79  $frontend->user->userGroupList = implode(',', $frontendUserAspect->get('groupIds'));
80  $frontend->user->userGroupIds = $frontendUserAspect->get('groupIds');
81  $enrichedVariables['frontend'] = $frontend;
82  }
83  $backendUserAspect = $this->context->getAspect('backend.user');
84  if ($backendUserAspect instanceof ‪UserAspect) {
85  $backend = new \stdClass();
86  $backend->user = new \stdClass();
87  $backend->user->isAdmin = $backendUserAspect->get('isAdmin');
88  $backend->user->isLoggedIn = $backendUserAspect->get('isLoggedIn');
89  $backend->user->userId = $backendUserAspect->get('id');
90  $backend->user->userGroupList = implode(',', $backendUserAspect->get('groupIds'));
91  $backend->user->userGroupIds = $backendUserAspect->get('groupIds');
92  $enrichedVariables['backend'] = $backend;
93  }
94  $workspaceAspect = $this->context->getAspect('workspace');
95  if ($workspaceAspect instanceof ‪WorkspaceAspect) {
96  $workspace = new \stdClass();
97  $workspace->workspaceId = $workspaceAspect->get('id');
98  $workspace->isLive = $workspaceAspect->get('isLive');
99  $workspace->isOffline = $workspaceAspect->get('isOffline');
100  $enrichedVariables['workspace'] = $workspace;
101  }
102 
103  $pageId = $variables['pageId'] ?? 0;
104 
105  // If rootLine is given, create an object that contains some prepared values.
106  $fullRootLine = $variables['fullRootLine'] ?? null;
107  if ($fullRootLine === null && $pageId > 0) {
108  $fullRootLine = BackendUtility::BEgetRootLine($pageId, '', true);
109  ksort($fullRootLine);
110  }
111  $localRootLine = $variables['localRootLine'] ?? $fullRootLine;
112  if (!empty($localRootLine)) {
113  $tree = new \stdClass();
114  $tree->level = count($localRootLine) - 1;
115  $tree->rootLine = $localRootLine;
116  $tree->fullRootLine = $fullRootLine;
117  $tree->rootLineIds = array_column($localRootLine, 'uid');
118  $tree->rootLineParentIds = array_slice(array_column($localRootLine, 'pid'), 1);
119  // We're feeding the "full" RootLine here, not the "local" one that stops at sys_template record having 'root' set.
120  // This is to be in-line with backend here: A 'backend_layout_next_level' on a page above sys_template 'root' page should
121  // still be considered. Normally, $fullRootLine is "deepest page first, then up". This is needed for getLayoutForPage() to find
122  // the 'nearest' parent. However, here it is always passed sorted, so it is a top-down rootLine. Hence, this needs to be once
123  // again reversed at this point.
124  $bottomUpFullRootLine = array_reverse($fullRootLine);
125  $tree->pagelayout = $this->pageLayoutResolver->getLayoutIdentifierForPage($variables['page'], $bottomUpFullRootLine);
126  $enrichedVariables['tree'] = $tree;
127  }
128 
129  // If a request is given, make sure it is an instance of RequestWrapper,
130  // if not, create an instance from ServerRequestInterface and set it.
131  if (isset($variables['request']) && !($variables['request'] instanceof ‪RequestWrapper)) {
132  $variables['request'] = new ‪RequestWrapper($variables['request']);
133  }
134 
135  // We do not expose pageId, rootLine and fullRootLine to conditions directly.
136  unset($variables['pageId'], $variables['localRootLine'], $variables['fullRootLine']);
137 
138  $enrichedVariables = array_replace($enrichedVariables, $variables);
139 
140  $this->resolver = new ‪Resolver('typoscript', $enrichedVariables);
141  }
142 
147  public function ‪getConditionListWithVerdicts(): array
148  {
150  }
151 
157  public function ‪visitBeforeChildren(‪IncludeInterface $include, int $currentDepth): void
158  {
159  if (!$include instanceof ‪IncludeConditionInterface) {
160  return;
161  }
162  $conditionExpression = $include->getConditionToken()->getValue();
163  try {
164  $verdict = (bool)$this->resolver->evaluate($conditionExpression);
165  } catch (SyntaxError) {
166  $this->logger->error('Expression could not be parsed.', ['expression' => $conditionExpression]);
167  $verdict = false;
168  }
169  if ($include->isConditionNegated()) {
170  // Honor ConditionElseInclude "[ELSE]" which negates the verdict of the main condition.
171  $verdict = !$verdict;
172  }
173  $this->conditionList[$conditionExpression] = $verdict;
174  $include->setConditionVerdict($verdict);
175  }
176 
177  public function ‪visit(‪IncludeInterface $include, int $currentDepth): void
178  {
179  // Noop, just implement interface
180  }
181 }
‪TYPO3\CMS\Core\ExpressionLanguage\RequestWrapper
Definition: RequestWrapper.php:36
‪TYPO3\CMS\Core\Context\WorkspaceAspect
Definition: WorkspaceAspect.php:31
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\visitBeforeChildren
‪visitBeforeChildren(IncludeInterface $include, int $currentDepth)
Definition: IncludeTreeConditionMatcherVisitor.php:157
‪TYPO3\CMS\Core\Page\PageLayoutResolver
Definition: PageLayoutResolver.php:42
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\$conditionList
‪array $conditionList
Definition: IncludeTreeConditionMatcherVisitor.php:48
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\__construct
‪__construct(private readonly Context $context, private readonly PageLayoutResolver $pageLayoutResolver,)
Definition: IncludeTreeConditionMatcherVisitor.php:50
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:54
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeVisitorInterface
Definition: IncludeTreeVisitorInterface.php:28
‪TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\IncludeConditionInterface
Definition: IncludeConditionInterface.php:32
‪TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\IncludeInterface
Definition: IncludeInterface.php:39
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\initializeExpressionMatcherWithVariables
‪initializeExpressionMatcherWithVariables(array $variables)
Definition: IncludeTreeConditionMatcherVisitor.php:66
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\getConditionListWithVerdicts
‪getConditionListWithVerdicts()
Definition: IncludeTreeConditionMatcherVisitor.php:147
‪TYPO3\CMS\Core\ExpressionLanguage\Resolver
Definition: Resolver.php:32
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\$resolver
‪Resolver $resolver
Definition: IncludeTreeConditionMatcherVisitor.php:47
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor
Definition: IncludeTreeAstBuilderVisitor.php:18
‪TYPO3\CMS\Core\Context\UserAspect
Definition: UserAspect.php:37
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor
Definition: IncludeTreeConditionMatcherVisitor.php:44
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor\visit
‪visit(IncludeInterface $include, int $currentDepth)
Definition: IncludeTreeConditionMatcherVisitor.php:177