[TASK] Extract displayCond functionality from FormEngine to new class
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / ElementConditionMatcher.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Sebastian Michaelsen (michaelsen@t3seo.de)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This copyright notice MUST APPEAR in all copies of the script!
27 ***************************************************************/
28
29 /**
30 * Class ElementConditionMatcher implements the TCA 'displayCond' option.
31 * The display condition is a colon separated string which describes
32 * the condition to decide whether a form field should be displayed.
33 */
34 class ElementConditionMatcher {
35
36 /**
37 * @var string
38 */
39 protected $flexformValueKey = '';
40
41 /**
42 * @var array
43 */
44 protected $record = array();
45
46 /**
47 * Evaluates the provided condition and returns TRUE if the form
48 * element should be displayed.
49 *
50 * The condition string is separated by colons and the first part
51 * indicates what type of evaluation should be performed.
52 *
53 * @param string $displayCondition
54 * @param array $record
55 * @param string $flexformValueKey
56 * @return boolean
57 */
58 public function match($displayCondition, array $record = array(), $flexformValueKey = '') {
59 $this->record = $record;
60 $this->flexformValueKey = $flexformValueKey;
61 $result = FALSE;
62 list($matchType, $condition) = explode(':', $displayCondition, 2);
63 switch ($matchType) {
64 case 'EXT':
65 $result = $this->matchExtensionCondition($condition);
66 break;
67 case 'FIELD':
68 $result = $this->matchFieldCondition($condition);
69 break;
70 case 'HIDE_FOR_NON_ADMINS':
71 $result = $this->matchHideForNonAdminsCondition();
72 break;
73 case 'HIDE_L10N_SIBLINGS':
74 $result = $this->matchHideL10nSiblingsCondition($condition);
75 break;
76 case 'REC':
77 $result = $this->matchRecordCondition($condition);
78 break;
79 case 'VERSION':
80 $result = $this->matchVersionCondition($condition);
81 break;
82 }
83 return $result;
84 }
85
86 /**
87 * Evaluates conditions concerning extensions
88 *
89 * Example:
90 * "EXT:saltedpasswords:LOADED:TRUE" => TRUE, if extension saltedpasswords is loaded.
91 *
92 * @param string $condition
93 * @return boolean
94 */
95 protected function matchExtensionCondition($condition) {
96 $result = FALSE;
97 list($extensionKey, $operator, $operand) = explode(':', $condition, 3);
98 if ($operator === 'LOADED') {
99 if (strtoupper($operand) === 'TRUE') {
100 $result = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($extensionKey);
101 } elseif (strtoupper($operand) === 'FALSE') {
102 $result = !\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($extensionKey);
103 }
104 }
105 return $result;
106 }
107
108 /**
109 * Evaluates conditions concerning a field of the current record.
110 * Requires a record set via ->setRecord()
111 *
112 * Example:
113 * "FIELD:sys_language_uid:>:0" => TRUE, if the field 'sys_language_uid' is greater than 0
114 *
115 * @param string $condition
116 * @return boolean
117 */
118 protected function matchFieldCondition($condition) {
119 list($fieldName, $operator, $operand) = explode(':', $condition, 3);
120 if ($this->flexformValueKey) {
121 if (strpos($fieldName, 'parentRec.') !== FALSE) {
122 $fieldNameParts = explode('.', $fieldName, 2);
123 $fieldValue = $this->record['parentRec'][$fieldNameParts[1]];
124 } else {
125 $fieldValue = $this->record[$fieldName][$this->flexformValueKey];
126 }
127 } else {
128 $fieldValue = $this->record[$fieldName];
129 }
130
131 $result = FALSE;
132 switch ($operator) {
133 case 'REQ':
134 if (strtoupper($operand) === 'TRUE') {
135 $result = (bool) $fieldValue;
136 } else {
137 $result = !$fieldValue;
138 }
139 break;
140 case '>':
141 $result = $fieldValue > $operand;
142 break;
143 case '<':
144 $result = $fieldValue < $operand;
145 break;
146 case '>=':
147 $result = $fieldValue >= $operand;
148 break;
149 case '<=':
150 $result = $fieldValue <= $operand;
151 break;
152 case '-':
153 case '!-':
154 list($minimum, $maximum) = explode('-', $operand);
155 $result = $fieldValue >= $minimum && $fieldValue <= $maximum;
156 if ($operator{0} === '!') {
157 $result = !$result;
158 }
159 break;
160 case 'IN':
161 case '!IN':
162 case '=':
163 case '!=':
164 $result = \TYPO3\CMS\Core\Utility\GeneralUtility::inList($operand, $fieldValue);
165 if ($operator{0} === '!') {
166 $result = !$result;
167 }
168 break;
169 }
170 return $result;
171 }
172
173 /**
174 * Evaluates TRUE if current backend user is an admin.
175 *
176 * @return boolean
177 */
178 protected function matchHideForNonAdminsCondition() {
179 return (bool) $this->getBackendUser()->isAdmin();
180 }
181
182 /**
183 * Evaluates whether the field is a value for the default language.
184 * Works only for <langChildren>=1, otherwise it has no effect.
185 *
186 * @param string $condition
187 * @return boolean
188 */
189 protected function matchHideL10nSiblingsCondition($condition) {
190 $result = FALSE;
191 if ($this->flexformValueKey === 'vDEF') {
192 $result = TRUE;
193 } elseif ($condition === 'except_admin' && $this->getBackendUser()->isAdmin()) {
194 $result = TRUE;
195 }
196 return $result;
197 }
198
199 /**
200 * Evaluates conditions concerning the status of the current record.
201 * Requires a record set via ->setRecord()
202 *
203 * Example:
204 * "REC:NEW:FALSE" => TRUE, if the record is already persisted (has a uid > 0)
205 *
206 * @param string $condition
207 * @return boolean
208 */
209 protected function matchRecordCondition($condition) {
210 $result = FALSE;
211 list($operator, $operand) = explode(':', $condition, 2);
212 if ($operator === 'NEW') {
213 if (strtoupper($operand) === 'TRUE') {
214 $result = !(intval($this->record['uid']) > 0);
215 } elseif (strtoupper($operand) === 'FALSE') {
216 $result = (intval($this->record['uid']) > 0);
217 }
218 }
219 return $result;
220 }
221
222 /**
223 * Evaluates whether the current record is versioned.
224 * Requires a record set via ->setRecord()
225 *
226 * @param string $condition
227 * @return boolean
228 */
229 protected function matchVersionCondition($condition) {
230 $result = FALSE;
231 list($operator, $operand) = explode(':', $condition, 2);
232 if ($operator === 'IS') {
233 $isNewRecord = !(intval($this->record['uid']) > 0);
234 // Detection of version can be done be detecting the workspace of the user
235 $isUserInWorkspace = $this->getBackendUser()->workspace > 0;
236 if (intval($this->record['pid']) == -1 || intval($this->record['_ORIG_pid']) == -1) {
237 $isRecordDetectedAsVersion = TRUE;
238 } else {
239 $isRecordDetectedAsVersion = FALSE;
240 }
241 // New records in a workspace are not handled as a version record
242 // if it's no new version, we detect versions like this:
243 // -- if user is in workspace: always TRUE
244 // -- if editor is in live ws: only TRUE if pid == -1
245 $isVersion = ($isUserInWorkspace || $isRecordDetectedAsVersion) && !$isNewRecord;
246 if (strtoupper($operand) === 'TRUE') {
247 $result = $isVersion;
248 } elseif (strtoupper($operand) === 'FALSE') {
249 $result = !$isVersion;
250 }
251 }
252 return $result;
253 }
254
255 /**
256 * Get current backend user
257 *
258 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
259 */
260 protected function getBackendUser() {
261 return $GLOBALS['BE_USER'];
262 }
263 }
264
265 ?>