‪TYPO3CMS  ‪main
AbstractConditionMatcher.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\Http\Message\ServerRequestInterface;
19 use Psr\Log\LoggerAwareInterface;
20 use Psr\Log\LoggerAwareTrait;
21 use Symfony\Component\ExpressionLanguage\SyntaxError;
27 
36 abstract class ‪AbstractConditionMatcher implements LoggerAwareInterface, ‪ConditionMatcherInterface
37 {
38  use LoggerAwareTrait;
39 
45  protected ‪$pageId;
46 
56  protected ‪$rootline;
57 
64  protected ‪$simulateMatchResult = false;
65 
73 
78 
83 
84  protected function ‪initializeExpressionLanguageResolver(): void
85  {
87  $this->expressionLanguageResolver = GeneralUtility::makeInstance(
88  Resolver::class,
89  'typoscript',
90  $this->expressionLanguageResolverVariables
91  );
92  }
93 
94  protected function ‪updateExpressionLanguageVariables(): void
95  {
96  // deliberately empty and not "abstract" due to backwards compatibility
97  // implement this method in derived classes
98  }
99 
105  public function ‪setPageId(‪$pageId)
106  {
107  if (is_int(‪$pageId) && ‪$pageId > 0) {
108  $this->pageId = ‪$pageId;
109  }
111  }
112 
118  public function ‪getPageId()
119  {
120  return ‪$this->pageId;
121  }
122 
128  public function ‪setRootline(array ‪$rootline)
129  {
130  if (!empty(‪$rootline)) {
131  $this->rootline = ‪$rootline;
132  }
134  }
135 
143  public function ‪getRootline()
144  {
145  return ‪$this->rootline;
146  }
147 
154  {
155  if (is_bool(‪$simulateMatchResult)) {
156  $this->simulateMatchResult = ‪$simulateMatchResult;
157  }
158  }
159 
166  {
167  $this->simulateMatchConditions = ‪$simulateMatchConditions;
168  }
169 
176  public function ‪match($expression): bool
177  {
178  // Return directly if result should be simulated:
179  if ($this->simulateMatchResult) {
181  }
182  // Return directly if matching for specific condition is simulated only:
183  if (!empty($this->simulateMatchConditions)) {
184  return in_array($expression, $this->simulateMatchConditions, true);
185  }
186  $result = false;
187  // First and last character must be square brackets:
188  if (str_starts_with($expression, '[') && str_ends_with($expression, ']')) {
189  $innerExpression = substr($expression, 1, -1);
190  $result = $this->‪evaluateExpression($innerExpression);
191  }
192  return $result;
193  }
194 
195  protected function ‪evaluateExpression(string $expression): bool
196  {
197  // The TypoScript [ELSE] condition is not known by the Symfony Expression Language and must not be evaluated.
198  // This is handled in the TypoScript parser tree builder logic.
199  if (strtoupper($expression) === 'ELSE') {
200  return false;
201  }
202 
203  try {
204  return (bool)$this->expressionLanguageResolver->evaluate($expression);
205  } catch (SyntaxError $exception) {
206  $message = 'Expression could not be parsed.';
207  $this->logger->error($message, ['expression' => $expression]);
208  } catch (\Throwable $exception) {
209  // The following error handling is required to mitigate a missing type check
210  // in the Symfony Expression Language handling. In case a condition
211  // use "in" or "not in" check in combination with a non array a PHP Warning
212  // is thrown. Example: [1 in "foo"] or ["bar" in "foo,baz"]
213  // This conditions are wrong for sure, but they will break the complete installation
214  // including the backend. To mitigate the problem we do the following:
215  // 1) In FE an InvalidTypoScriptConditionException is thrown (if strictSyntax is enabled)
216  // 2) In FE silent catch this error and log it (if strictSyntax is disabled)
217  // 3) In BE silent catch this error and log it, but never break the backend.
218  $this->logger->error($exception->getMessage(), [
219  'expression' => $expression,
220  'exception' => $exception,
221  ]);
222  if ((‪$GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
223  && ‪ApplicationType::fromRequest(‪$GLOBALS['TYPO3_REQUEST'])->isFrontend()
224  && $exception instanceof Exception
225  && str_contains($exception->getMessage(), 'in_array() expects parameter 2 to be array')
226  ) {
227  throw new InvalidTypoScriptConditionException('Invalid expression in condition: [' . $expression . ']', 1536950931);
228  }
229  }
230  return false;
231  }
232 }
‪TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException
Definition: InvalidTypoScriptConditionException.php:27
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\setRootline
‪setRootline(array $rootline)
Definition: AbstractConditionMatcher.php:122
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\match
‪bool match($expression)
Definition: AbstractConditionMatcher.php:170
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\$simulateMatchResult
‪bool $simulateMatchResult
Definition: AbstractConditionMatcher.php:61
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\$pageId
‪int $pageId
Definition: AbstractConditionMatcher.php:44
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\getPageId
‪int getPageId()
Definition: AbstractConditionMatcher.php:112
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\$simulateMatchConditions
‪array $simulateMatchConditions
Definition: AbstractConditionMatcher.php:68
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\setSimulateMatchResult
‪setSimulateMatchResult($simulateMatchResult)
Definition: AbstractConditionMatcher.php:147
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher
Definition: AbstractConditionMatcher.php:37
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\$rootline
‪array $rootline
Definition: AbstractConditionMatcher.php:54
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\ConditionMatcherInterface
Definition: ConditionMatcherInterface.php:26
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\setSimulateMatchConditions
‪setSimulateMatchConditions(array $simulateMatchConditions)
Definition: AbstractConditionMatcher.php:159
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\getRootline
‪array getRootline()
Definition: AbstractConditionMatcher.php:137
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\updateExpressionLanguageVariables
‪updateExpressionLanguageVariables()
Definition: AbstractConditionMatcher.php:88
‪TYPO3\CMS\Core\Error\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\initializeExpressionLanguageResolver
‪initializeExpressionLanguageResolver()
Definition: AbstractConditionMatcher.php:78
‪TYPO3\CMS\Core\ExpressionLanguage\Resolver
Definition: Resolver.php:32
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\$expressionLanguageResolverVariables
‪array $expressionLanguageResolverVariables
Definition: AbstractConditionMatcher.php:76
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\evaluateExpression
‪evaluateExpression(string $expression)
Definition: AbstractConditionMatcher.php:189
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Http\fromRequest
‪@ fromRequest
Definition: ApplicationType.php:67
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\$expressionLanguageResolver
‪Resolver $expressionLanguageResolver
Definition: AbstractConditionMatcher.php:72
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching
Definition: AbstractConditionMatcher.php:16
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher\setPageId
‪setPageId($pageId)
Definition: AbstractConditionMatcher.php:99
‪TYPO3\CMS\Core\Http\ApplicationType
‪ApplicationType
Definition: ApplicationType.php:56