[TASK] Streamline expressionLanguage usage in core
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Configuration / TypoScript / ConditionMatching / ConditionMatcher.php
1 <?php
2 namespace TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Controller\EditDocumentController;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23
24 /**
25 * Matching TypoScript conditions for backend disposal.
26 *
27 * Used with the TypoScript parser.
28 * Matches browserinfo, IPnumbers for use with templates
29 */
30 class ConditionMatcher extends AbstractConditionMatcher
31 {
32 /**
33 * @var Context
34 */
35 protected $context;
36
37 public function __construct(Context $context = null)
38 {
39 $this->context = $context ?? GeneralUtility::makeInstance(Context::class);
40 $this->rootline = $this->determineRootline() ?? [];
41 $treeLevel = $this->rootline ? count($this->rootline) - 1 : 0;
42 if ($this->isNewPageWithPageId($this->pageId)) {
43 $treeLevel++;
44 }
45 $tree = new \stdClass();
46 $tree->level = $treeLevel;
47 $tree->rootLine = $this->rootline;
48 $tree->rootLineIds = array_column($this->rootline, 'uid');
49
50 $backendUserAspect = $this->context->getAspect('backend.user');
51 $backend = new \stdClass();
52 $backend->user = new \stdClass();
53 $backend->user->isAdmin = $backendUserAspect->get('isAdmin') ?? false;
54 $backend->user->isLoggedIn = $backendUserAspect->get('isLoggedIn') ?? false;
55 $backend->user->userId = $backendUserAspect->get('id') ?? 0;
56 $backend->user->userGroupList = implode(',', $backendUserAspect->get('groupIds'));
57
58 $this->expressionLanguageResolver = GeneralUtility::makeInstance(
59 Resolver::class,
60 'typoscript',
61 [
62 'tree' => $tree,
63 'backend' => $backend,
64 'page' => $this->getPage(),
65 ]
66 );
67 }
68
69 /**
70 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
71 *
72 * @param string $string The condition to match against its criteria.
73 * @return bool Whether the condition matched
74 * @see \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::parse()
75 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
76 */
77 protected function evaluateCondition($string)
78 {
79 if ($this->strictSyntaxEnabled()) {
80 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);
81 }
82
83 list($key, $value) = GeneralUtility::trimExplode('=', $string, false, 2);
84 $result = $this->evaluateConditionCommon($key, $value);
85 if (is_bool($result)) {
86 return $result;
87 }
88
89 switch ($key) {
90 case 'usergroup':
91 $groupList = $this->getGroupList();
92 $values = GeneralUtility::trimExplode(',', $value, true);
93 foreach ($values as $test) {
94 if ($test === '*' || GeneralUtility::inList($groupList, $test)) {
95 return true;
96 }
97 }
98 break;
99 case 'adminUser':
100 if ($this->isUserLoggedIn()) {
101 return !((bool)$value xor $this->isAdminUser());
102 }
103 break;
104 case 'treeLevel':
105 $values = GeneralUtility::trimExplode(',', $value, true);
106 $treeLevel = count($this->rootline) - 1;
107 // If a new page is being edited or saved the treeLevel is higher by one:
108 if ($this->isNewPageWithPageId($this->pageId)) {
109 $treeLevel++;
110 }
111 foreach ($values as $test) {
112 if ($test == $treeLevel) {
113 return true;
114 }
115 }
116 break;
117 case 'PIDupinRootline':
118 case 'PIDinRootline':
119 $values = GeneralUtility::trimExplode(',', $value, true);
120 if ($key === 'PIDinRootline' || !in_array($this->pageId, $values) || $this->isNewPageWithPageId($this->pageId)) {
121 foreach ($values as $test) {
122 foreach ($this->rootline as $rl_dat) {
123 if ($rl_dat['uid'] == $test) {
124 return true;
125 }
126 }
127 }
128 }
129 break;
130 default:
131 $conditionResult = $this->evaluateCustomDefinedCondition($string);
132 if ($conditionResult !== null) {
133 return $conditionResult;
134 }
135 }
136
137 return false;
138 }
139
140 /**
141 * Returns GP / ENV vars
142 *
143 * @param string $var Identifier
144 * @return mixed The value of the variable pointed to or NULL if variable did not exist
145 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
146 */
147 protected function getVariable($var)
148 {
149 $vars = explode(':', $var, 2);
150 return $this->getVariableCommon($vars);
151 }
152
153 /**
154 * Get the usergroup list of the current user.
155 *
156 * @return string The usergroup list of the current user
157 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
158 */
159 protected function getGroupList()
160 {
161 return $this->getBackendUserAuthentication()->groupList;
162 }
163
164 /**
165 * Tries to determine the ID of the page currently processed.
166 * When User/Group TS-Config is parsed when no specific page is handled
167 * (i.e. in the Extension Manager, etc.) this function will return "0", so that
168 * the accordant conditions (e.g. PIDinRootline) will return "FALSE"
169 *
170 * @return int The determined page id or otherwise 0
171 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
172 */
173 protected function determinePageId()
174 {
175 $pageId = 0;
176 $editStatement = GeneralUtility::_GP('edit');
177 $commandStatement = GeneralUtility::_GP('cmd');
178 // Determine id from module that was called with an id:
179 if ($id = (int)GeneralUtility::_GP('id')) {
180 $pageId = $id;
181 } elseif (is_array($editStatement)) {
182 $table = key($editStatement);
183 $uidAndAction = current($editStatement);
184 $uid = key($uidAndAction);
185 $action = current($uidAndAction);
186 if ($action === 'edit') {
187 $pageId = $this->getPageIdByRecord($table, $uid);
188 } elseif ($action === 'new') {
189 $pageId = $this->getPageIdByRecord($table, $uid, true);
190 }
191 } elseif (is_array($commandStatement)) {
192 $table = key($commandStatement);
193 $uidActionAndTarget = current($commandStatement);
194 $uid = key($uidActionAndTarget);
195 $actionAndTarget = current($uidActionAndTarget);
196 $action = key($actionAndTarget);
197 $target = current($actionAndTarget);
198 if ($action === 'delete') {
199 $pageId = $this->getPageIdByRecord($table, $uid);
200 } elseif ($action === 'copy' || $action === 'move') {
201 $pageId = $this->getPageIdByRecord($table, $target, true);
202 }
203 }
204 return $pageId;
205 }
206
207 /**
208 * Gets the properties for the current page.
209 *
210 * @return array The properties for the current page.
211 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
212 */
213 protected function getPage()
214 {
215 $pageId = $this->pageId ?? $this->determinePageId();
216 return BackendUtility::getRecord('pages', $pageId) ?? [];
217 }
218
219 /**
220 * Gets the page id by a record.
221 *
222 * @param string $table Name of the table
223 * @param int $id Id of the accordant record
224 * @param bool $ignoreTable Whether to ignore the page, if TRUE a positive
225 * @return int Id of the page the record is persisted on
226 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
227 */
228 protected function getPageIdByRecord($table, $id, $ignoreTable = false)
229 {
230 $pageId = 0;
231 $id = (int)$id;
232 if ($table && $id) {
233 if (($ignoreTable || $table === 'pages') && $id >= 0) {
234 $pageId = $id;
235 } else {
236 $record = BackendUtility::getRecordWSOL($table, abs($id), '*', '', false);
237 $pageId = $record['pid'];
238 }
239 }
240 return $pageId;
241 }
242
243 /**
244 * Determine if record of table 'pages' with the given $pid is currently created in TCEforms.
245 * This information is required for conditions in BE for PIDupinRootline.
246 *
247 * @param int $pageId The pid the check for as parent page
248 * @return bool TRUE if the is currently a new page record being edited with $pid as uid of the parent page
249 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
250 */
251 protected function isNewPageWithPageId($pageId)
252 {
253 if (isset($GLOBALS['SOBE']) && $GLOBALS['SOBE'] instanceof EditDocumentController) {
254 $pageId = (int)$pageId;
255 $elementsData = $GLOBALS['SOBE']->elementsData;
256 $data = $GLOBALS['SOBE']->data;
257 // If saving a new page record:
258 if (is_array($data) && isset($data['pages']) && is_array($data['pages'])) {
259 foreach ($data['pages'] as $uid => $fields) {
260 if (strpos($uid, 'NEW') === 0 && $fields['pid'] == $pageId) {
261 return true;
262 }
263 }
264 }
265 // If editing a new page record (not saved yet):
266 if (is_array($elementsData)) {
267 foreach ($elementsData as $element) {
268 if ($element['cmd'] === 'new' && $element['table'] === 'pages') {
269 if ($element['pid'] < 0) {
270 $pageRecord = BackendUtility::getRecord('pages', abs($element['pid']), 'pid');
271 $element['pid'] = $pageRecord['pid'];
272 }
273 if ($element['pid'] == $pageId) {
274 return true;
275 }
276 }
277 }
278 }
279 }
280 return false;
281 }
282
283 /**
284 * Determines the rootline for the current page.
285 *
286 * @return array The rootline for the current page.
287 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
288 */
289 protected function determineRootline()
290 {
291 $pageId = $this->pageId ?? $this->determinePageId();
292 return BackendUtility::BEgetRootLine($pageId, '', true);
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()
302 {
303 return $this->getBackendUserAuthentication()->user['uid'];
304 }
305
306 /**
307 * Determines if a user is logged in.
308 *
309 * @return bool Determines if a user is logged in
310 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
311 */
312 protected function isUserLoggedIn()
313 {
314 return (bool)$this->getBackendUserAuthentication()->user['uid'];
315 }
316
317 /**
318 * Determines whether the current user is admin.
319 *
320 * @return bool Whether the current user is admin
321 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
322 */
323 protected function isAdminUser()
324 {
325 return $this->getBackendUserAuthentication()->isAdmin();
326 }
327
328 /**
329 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
330 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
331 */
332 protected function getBackendUserAuthentication()
333 {
334 return $GLOBALS['BE_USER'] ?? null;
335 }
336 }