[TASK] Streamline expressionLanguage usage in core
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Configuration / TypoScript / ConditionMatching / ConditionMatcher.php
1 <?php
2
3 namespace TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching;
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
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\Context\UserAspect;
22 use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
23 use TYPO3\CMS\Core\Site\Entity\Site;
24 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27 /**
28 * Matching TypoScript conditions for frontend disposal.
29 *
30 * Used with the TypoScript parser. Matches browserinfo
31 * and IP numbers for use with templates.
32 */
33 class ConditionMatcher extends AbstractConditionMatcher
34 {
35 /**
36 * @var Context
37 */
38 protected $context;
39
40 /**
41 * @param Context $context optional context to fetch data from
42 */
43 public function __construct(Context $context = null)
44 {
45 $this->context = $context ?? GeneralUtility::makeInstance(Context::class);
46 $this->rootline = $this->determineRootline();
47 $tree = new \stdClass();
48 $tree->level = $this->rootline ? count($this->rootline) - 1 : 0;
49 $tree->rootLine = $this->rootline;
50 $tree->rootLineIds = array_column($this->rootline, 'uid');
51
52 $frontendUserAspect = $this->context->getAspect('frontend.user');
53 $frontend = new \stdClass();
54 $frontend->user = new \stdClass();
55 $frontend->user->isLoggedIn = $frontendUserAspect->get('isLoggedIn') ?? false;
56 $frontend->user->userId = $frontendUserAspect->get('id') ?? 0;
57 $frontend->user->userGroupList = implode(',', $frontendUserAspect->get('groupIds'));
58
59 $this->expressionLanguageResolver = GeneralUtility::makeInstance(
60 Resolver::class,
61 'typoscript',
62 [
63 'tree' => $tree,
64 'frontend' => $frontend,
65 'page' => $this->getPage(),
66 ]
67 );
68 }
69
70 /**
71 * Evaluates a TypoScript condition given as input,
72 * eg. "[browser=net][...(other conditions)...]"
73 *
74 * @param string $string The condition to match against its criteria.
75 * @return bool Whether the condition matched
76 * @see \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::parse()
77 * @throws \TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException
78 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
79 */
80 protected function evaluateCondition($string)
81 {
82 if ($this->strictSyntaxEnabled()) {
83 trigger_error('The old condition syntax has been deprecated and will be removed in TYPO3 CMS 10, use the new expression language. condition: [' . $string . ']', E_USER_DEPRECATED);
84 }
85
86 list($key, $value) = GeneralUtility::trimExplode('=', $string, false, 2);
87 $result = $this->evaluateConditionCommon($key, $value);
88 if (is_bool($result)) {
89 return $result;
90 }
91
92 switch ($key) {
93 case 'usergroup':
94 $groupList = $this->getGroupList();
95 // '0,-1' is the default usergroups when not logged in!
96 if ($groupList !== '0,-1') {
97 $values = GeneralUtility::trimExplode(',', $value, true);
98 foreach ($values as $test) {
99 if ($test === '*' || GeneralUtility::inList($groupList, $test)) {
100 return true;
101 }
102 }
103 }
104 break;
105 case 'treeLevel':
106 $values = GeneralUtility::trimExplode(',', $value, true);
107 $treeLevel = count($this->rootline) - 1;
108 foreach ($values as $test) {
109 if ($test == $treeLevel) {
110 return true;
111 }
112 }
113 break;
114 case 'PIDupinRootline':
115 case 'PIDinRootline':
116 $values = GeneralUtility::trimExplode(',', $value, true);
117 if ($key === 'PIDinRootline' || !in_array($this->pageId, $values)) {
118 foreach ($values as $test) {
119 foreach ($this->rootline as $rlDat) {
120 if ($rlDat['uid'] == $test) {
121 return true;
122 }
123 }
124 }
125 }
126 break;
127 case 'site':
128 $site = $this->getCurrentSite();
129 if ($site instanceof Site) {
130 $values = GeneralUtility::trimExplode(',', $value, true);
131 foreach ($values as $test) {
132 $point = strcspn($test, '=');
133 $testValue = substr($test, $point + 1);
134 $testValue = trim($testValue);
135 $theVarName = trim(substr($test, 0, $point));
136 $methodName = 'get' . ucfirst($theVarName);
137 if (method_exists($site, $methodName)) {
138 $sitePropertyValue = call_user_func([$site, $methodName]);
139 // loose check on purpose in order to check for integer values
140 if ($testValue == $sitePropertyValue) {
141 return true;
142 }
143 }
144 }
145 }
146 break;
147 case 'siteLanguage':
148 $siteLanguage = $this->getCurrentSiteLanguage();
149 if ($siteLanguage instanceof SiteLanguage) {
150 $values = GeneralUtility::trimExplode(',', $value, true);
151 foreach ($values as $test) {
152 $point = strcspn($test, '=');
153 $testValue = substr($test, $point + 1);
154 $testValue = trim($testValue);
155 $theVarName = trim(substr($test, 0, $point));
156 $methodName = 'get' . ucfirst($theVarName);
157 if (method_exists($siteLanguage, $methodName)) {
158 $languagePropertyValue = call_user_func([$siteLanguage, $methodName]);
159 // loose check on purpose in order to check for integer values
160 if ($testValue == $languagePropertyValue) {
161 return true;
162 }
163 }
164 }
165 }
166 break;
167 default:
168 $conditionResult = $this->evaluateCustomDefinedCondition($string);
169 if ($conditionResult !== null) {
170 return $conditionResult;
171 }
172 }
173
174 return false;
175 }
176
177 /**
178 * Returns GP / ENV / TSFE / session vars
179 *
180 * @example GP:L
181 * @example TSFE:fe_user|sesData|foo|bar
182 * @example TSFE:id
183 * @example ENV:HTTP_HOST
184 *
185 * @param string $var Identifier
186 * @return mixed|null The value of the variable pointed to or NULL if variable did not exist
187 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
188 */
189 protected function getVariable($var)
190 {
191 $vars = explode(':', $var, 2);
192 $val = $this->getVariableCommon($vars);
193 if ($val === null) {
194 $splitAgain = explode('|', $vars[1], 2);
195 $k = trim($splitAgain[0]);
196 if ($k) {
197 switch ((string)trim($vars[0])) {
198 case 'TSFE':
199 if (strpos($vars[1], 'fe_user|sesData|') === 0) {
200 trigger_error(
201 'Condition on TSFE|fe_user|sesData is deprecated and will be removed in TYPO3 CMS 10',
202 E_USER_DEPRECATED
203 );
204 $val = $this->getSessionVariable(substr($vars[1], 16));
205 } else {
206 $val = $this->getGlobal('TSFE|' . $vars[1]);
207 }
208 break;
209 case 'session':
210 $val = $this->getSessionVariable($vars[1]);
211 break;
212 default:
213 }
214 }
215 }
216 return $val;
217 }
218
219 /**
220 * Return variable from current frontend user session
221 *
222 * @param string $var Session key
223 * @return mixed|null The value of the variable pointed to or NULL if variable did not exist
224 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
225 */
226 protected function getSessionVariable(string $var)
227 {
228 $retVal = null;
229 $keyParts = explode('|', $var);
230 $sessionKey = array_shift($keyParts);
231 $tsfe = $this->getTypoScriptFrontendController();
232 if ($tsfe && is_object($tsfe->fe_user)) {
233 $retVal = $tsfe->fe_user->getSessionData($sessionKey);
234 foreach ($keyParts as $keyPart) {
235 if (is_object($retVal)) {
236 $retVal = $retVal->{$keyPart};
237 } elseif (is_array($retVal)) {
238 $retVal = $retVal[$keyPart];
239 } else {
240 break;
241 }
242 }
243 }
244 return $retVal;
245 }
246
247 /**
248 * Get the usergroup list of the current user.
249 *
250 * @return string The usergroup list of the current user
251 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
252 */
253 protected function getGroupList(): string
254 {
255 /** @var UserAspect $userAspect */
256 $userAspect = $this->context->getAspect('frontend.user');
257 return implode(',', $userAspect->getGroupIds());
258 }
259
260 /**
261 * Determines the current page Id.
262 *
263 * @return int The current page Id
264 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
265 */
266 protected function determinePageId()
267 {
268 return (int)($this->getTypoScriptFrontendController()->id ?? 0);
269 }
270
271 /**
272 * Gets the properties for the current page.
273 *
274 * @return array The properties for the current page.
275 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
276 */
277 protected function getPage()
278 {
279 return is_array($this->getTypoScriptFrontendController()->page)
280 ? $this->getTypoScriptFrontendController()->page
281 : [];
282 }
283
284 /**
285 * Determines the rootline for the current page.
286 *
287 * @return array The rootline for the current page.
288 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
289 */
290 protected function determineRootline()
291 {
292 return (array)$this->getTypoScriptFrontendController()->tmpl->rootLine;
293 }
294
295 /**
296 * Get the id of the current user.
297 *
298 * @return int The id of the current user
299 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
300 */
301 protected function getUserId(): int
302 {
303 $userAspect = $this->context->getAspect('frontend.user');
304 return $userAspect->get('id');
305 }
306
307 /**
308 * Determines if a user is logged in.
309 *
310 * @return bool Determines if a user is logged in
311 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
312 */
313 protected function isUserLoggedIn(): bool
314 {
315 /** @var UserAspect $userAspect */
316 $userAspect = $this->context->getAspect('frontend.user');
317 return $userAspect->isLoggedIn();
318 }
319
320 /**
321 * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
322 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
323 */
324 protected function getTypoScriptFrontendController()
325 {
326 return $GLOBALS['TSFE'];
327 }
328
329 /**
330 * Returns the currently configured "site language" if a site is configured (= resolved) in the current request.
331 *
332 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
333 */
334 protected function getCurrentSiteLanguage(): ?SiteLanguage
335 {
336 if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
337 && $GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof SiteLanguage) {
338 return $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
339 }
340 return null;
341 }
342
343 /**
344 * Returns the currently configured site if a site is configured (= resolved) in the current request.
345 *
346 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
347 */
348 protected function getCurrentSite(): ?Site
349 {
350 if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
351 && $GLOBALS['TYPO3_REQUEST']->getAttribute('site') instanceof Site) {
352 return $GLOBALS['TYPO3_REQUEST']->getAttribute('site');
353 }
354 return null;
355 }
356 }