9efa3b827f4a842267f1f312e99f07cadb78b11f
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FlexFormsHelper.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
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\Core\Utility\GeneralUtility;
18
19 /**
20 * Contains FlexForm manipulation methods as part of the TCEforms
21 *
22 * @author Kai Vogel <kai.vogel(at)speedprogs.de>
23 */
24 class FlexFormsHelper extends \TYPO3\CMS\Backend\Form\FormEngine {
25
26 /**
27 * Options that will be removed from config after creating items for a select to prevent double parsing
28 *
29 * @var array
30 */
31 protected $removeSelectConfig = array(
32 'itemsProcFunc',
33 'foreign_table',
34 'foreign_table_where',
35 'foreign_table_prefix',
36 'foreign_table_loadIcons',
37 'neg_foreign_table',
38 'neg_foreign_table_where',
39 'neg_foreign_table_prefix',
40 'neg_foreign_table_loadIcons',
41 'neg_foreign_table_imposeValueField',
42 'fileFolder',
43 'fileFolder_extList',
44 'fileFolder_recursions',
45 'MM',
46 'MM_opposite_field',
47 'MM_match_fields',
48 'MM_insert_fields',
49 'MM_table_where',
50 'MM_hasUidField',
51 'special'
52 );
53
54 /**
55 * Modify the Data Structure of a FlexForm field via TSconfig and group access lists
56 *
57 * @param array $dataStructure The data structure of the FlexForm field
58 * @param string $table The table name of the record
59 * @param string $tableField The field name
60 * @param array $tableRow The record data
61 * @param array $tableConf Additional configuration options
62 * @return array Modified FlexForm DS
63 * @see \TYPO3\CMS\Backend\Form\FormEngine::getSingleField_typeFlex()
64 */
65 public function modifyFlexFormDS(array $dataStructure, $table, $tableField, array $tableRow, array $tableConf) {
66 $singleSheet = !isset($dataStructure['sheets']) || !is_array($dataStructure['sheets']);
67 $metaConf = !empty($dataStructure['meta']) ? $dataStructure['meta'] : array();
68 $sheetConf = array();
69 // Get extension identifier (uses second pointer field if it's value is not empty,
70 // "list" or "*", else it must be a plugin and first one will be used)
71 $pointerFields = !empty($tableConf['config']['ds_pointerField']) ? $tableConf['config']['ds_pointerField'] : 'list_type,CType';
72 $pointerFields = GeneralUtility::trimExplode(',', $pointerFields);
73 $flexformIdentifier = !empty($tableRow[$pointerFields[0]]) ? $tableRow[$pointerFields[0]] : '';
74 if (!empty($tableRow[$pointerFields[1]]) && $tableRow[$pointerFields[1]] != 'list' && $tableRow[$pointerFields[1]] != '*') {
75 $flexformIdentifier = $tableRow[$pointerFields[1]];
76 }
77 if (empty($flexformIdentifier)) {
78 return $dataStructure;
79 }
80 // Get field configuration from page TSConfig
81 $TSconfig = $this->setTSconfig($table, $tableRow);
82 if (!empty($TSconfig[$tableField][($flexformIdentifier . '.')])) {
83 $sheetConf = GeneralUtility::removeDotsFromTS($TSconfig[$tableField][$flexformIdentifier . '.']);
84 }
85 // Get non-exclude-fields from group access lists
86 $nonExcludeFields = $this->getFlexFormNonExcludeFields($table, $tableField, $flexformIdentifier);
87 // Load complete DS, including external file references
88 $dataStructure = GeneralUtility::resolveAllSheetsInDS($dataStructure);
89 // Modify language handling in meta configuration
90 if (isset($sheetConf['langDisable'])) {
91 $metaConf['langDisable'] = $sheetConf['langDisable'];
92 }
93 if (isset($sheetConf['langChildren'])) {
94 $metaConf['langChildren'] = $sheetConf['langChildren'];
95 }
96 // Modify flexform sheets
97 foreach ($dataStructure['sheets'] as $sheetName => $sheet) {
98 if (empty($sheet['ROOT']['el']) || !is_array($sheet['ROOT']['el'])) {
99 continue;
100 }
101 // Remove whole sheet (tab) if disabled
102 if (!empty($sheetConf[$sheetName]['disabled'])) {
103 unset($dataStructure['sheets'][$sheetName]);
104 continue;
105 }
106 // Rename sheet (tab)
107 if (!empty($sheetConf[$sheetName]['sheetTitle'])) {
108 $dataStructure['sheets'][$sheetName]['ROOT']['TCEforms']['sheetTitle'] = $sheetConf[$sheetName]['sheetTitle'];
109 }
110 // Set sheet description (tab)
111 if (!empty($sheetConf[$sheetName]['sheetDescription'])) {
112 $dataStructure['sheets'][$sheetName]['ROOT']['TCEforms']['sheetDescription'] = $sheetConf[$sheetName]['sheetDescription'];
113 }
114 // Set sheet short description (tab)
115 if (!empty($sheetConf[$sheetName]['sheetShortDescr'])) {
116 $dataStructure['sheets'][$sheetName]['ROOT']['TCEforms']['sheetShortDescr'] = $sheetConf[$sheetName]['sheetShortDescr'];
117 }
118 // Modify all configured fields in sheet (tab)
119 $dataStructure['sheets'][$sheetName]['ROOT']['el'] = $this->modifySingleFlexFormSheet($sheet['ROOT']['el'], $table, $tableField, $tableRow, !empty($sheetConf[$sheetName]) ? $sheetConf[$sheetName] : array(), !empty($nonExcludeFields[$sheetName]) ? $nonExcludeFields[$sheetName] : array());
120 // Remove empty sheet (tab)
121 if (empty($dataStructure['sheets'][$sheetName]['ROOT']['el'])) {
122 unset($dataStructure['sheets'][$sheetName]);
123 }
124 }
125 // Recover single flexform structure
126 if ($singleSheet && isset($dataStructure['sheets']['sDEF'])) {
127 $dataStructure = $dataStructure['sheets']['sDEF'];
128 }
129 // Recover meta configuration
130 if (!empty($metaConf)) {
131 $dataStructure['meta'] = $metaConf;
132 }
133 return $dataStructure;
134 }
135
136 /**
137 * Modify a single FlexForm sheet according to given configuration
138 *
139 * @param array $sheet Flexform sheet to manipulate
140 * @param string $table The table name
141 * @param string $tableField The field name
142 * @param array $tableRow The record data
143 * @param array $sheetConf Sheet configuration
144 * @param array $nonExcludeFields Non-exclude-fields for this sheet
145 * @return array Modified sheet
146 * @see \TYPO3\CMS\Backend\Form\FlexFormsHelper::modifyFlexFormDS()
147 */
148 public function modifySingleFlexFormSheet(array $sheet, $table, $tableField, array $tableRow, array $sheetConf, array $nonExcludeFields) {
149 if (empty($sheet) || empty($table) || empty($tableField) || empty($tableRow)) {
150 return $sheet;
151 }
152 // Modify fields
153 foreach ($sheet as $fieldName => $field) {
154 // Remove excluded fields
155 if (!$GLOBALS['BE_USER']->isAdmin() && !empty($field['TCEforms']['exclude']) && empty($nonExcludeFields[$fieldName])) {
156 unset($sheet[$fieldName]);
157 continue;
158 }
159 // Stop here if no TSConfig was found for this field
160 if (empty($sheetConf[$fieldName]) || !is_array($sheetConf[$fieldName])) {
161 continue;
162 }
163 // Remove disabled fields
164 if (!empty($sheetConf[$fieldName]['disabled'])) {
165 unset($sheet[$fieldName]);
166 continue;
167 }
168 $fieldConf = $sheetConf[$fieldName];
169 $removeItems = !empty($fieldConf['removeItems']) ? GeneralUtility::trimExplode(',', $fieldConf['removeItems'], TRUE) : array();
170 $keepItems = !empty($fieldConf['keepItems']) ? GeneralUtility::trimExplode(',', $fieldConf['keepItems'], TRUE) : array();
171 $renameItems = !empty($fieldConf['altLabels']) && is_array($fieldConf['altLabels']) ? $fieldConf['altLabels'] : array();
172 $addItems = !empty($fieldConf['addItems']) && is_array($fieldConf['addItems']) ? $fieldConf['addItems'] : array();
173 unset($fieldConf['removeItems']);
174 unset($fieldConf['keepItems']);
175 unset($fieldConf['altLabels']);
176 unset($fieldConf['addItems']);
177 // Manipulate field
178 if (!empty($field['TCEforms']) && is_array($field['TCEforms'])) {
179 $sheet[$fieldName]['TCEforms'] = $field['TCEforms'];
180 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($sheet[$fieldName]['TCEforms'], $fieldConf);
181 }
182 // Manipulate only select fields, other field types will stop here
183 if (empty($field['TCEforms']['config']['type']) || $field['TCEforms']['config']['type'] != 'select') {
184 continue;
185 }
186 // Getting the selector box items from system
187 $selItems = $this->addSelectOptionsToItemArray($this->initItemArray($field['TCEforms']), $field['TCEforms'], $this->setTSconfig($table, $tableRow), $tableField);
188
189 // Possibly filter some items
190 $selItems = GeneralUtility::keepItemsInArray(
191 $selItems,
192 $keepItems,
193 function ($value) {
194 return $value[1];
195 }
196 );
197
198 // Possibly add some items
199 $selItems = $this->addItems($selItems, $addItems);
200 // Process items by a user function
201 if (!empty($field['TCEforms']['config']['itemsProcFunc'])) {
202 $selItems = $this->procItems($selItems, $fieldConf['config'], $field['TCEforms']['config'], $table, $tableRow, $tableField);
203 }
204 // Remove special configuration options after creating items to prevent double parsing
205 foreach ($this->removeSelectConfig as $option) {
206 unset($sheet[$fieldName]['TCEforms']['config'][$option]);
207 }
208 // Rename and remove items in select
209 if ((!empty($removeItems) || !empty($renameItems)) && !empty($selItems) && is_array($selItems)) {
210 foreach ($selItems as $itemKey => $itemConf) {
211 // Option has no key, no manipulation possible
212 if (!isset($itemConf[1])) {
213 continue;
214 }
215 // Remove
216 foreach ($removeItems as $removeKey => $removeValue) {
217 if (strcasecmp($removeValue, $itemConf[1]) == 0) {
218 unset($selItems[$itemKey]);
219 unset($removeItems[$removeKey]);
220 }
221 }
222 // Rename
223 foreach ($renameItems as $renameKey => $renameValue) {
224 if (strcasecmp($renameKey, $itemConf[1]) == 0) {
225 $selItems[$itemKey][0] = htmlspecialchars($renameValue);
226 unset($renameItems[$renameKey]);
227 }
228 }
229 }
230 }
231 $sheet[$fieldName]['TCEforms']['config']['items'] = $selItems;
232 }
233 return $sheet;
234 }
235
236 /**
237 * Get FlexForm non-exclude-fields for current backend user
238 *
239 * @param string $table The table name
240 * @param string $tableField The field name
241 * @param string $extIdent The extension identifier
242 * @return array All non_exclude_fields from FlexForms
243 * @see \TYPO3\CMS\Backend\Form\FormEngine::getSingleField_typeFlex()
244 */
245 protected function getFlexFormNonExcludeFields($table, $tableField, $extIdent) {
246 if (empty($GLOBALS['BE_USER']->groupData['non_exclude_fields']) || empty($table) || empty($tableField) || empty($extIdent)) {
247 return array();
248 }
249 $accessListFields = GeneralUtility::trimExplode(',', $GLOBALS['BE_USER']->groupData['non_exclude_fields']);
250 $identPrefix = $table . ':' . $tableField . ';' . $extIdent . ';';
251 $nonExcludeFields = array();
252 // Collect only FlexForm fields
253 foreach ($accessListFields as $field) {
254 if (strpos($field, $identPrefix) !== FALSE) {
255 list(, , $sheetName, $fieldName) = explode(';', $field);
256 $nonExcludeFields[$sheetName][$fieldName] = TRUE;
257 }
258 }
259 return $nonExcludeFields;
260 }
261
262 /**
263 * Compare two arrays by their first value
264 *
265 * @param array $array1 First array
266 * @param array $array2 Second array
267 * @return integer Negative int if first array is lower, zero if both are identical, and positive if second is higher
268 */
269 static public function compareArraysByFirstValue(array $array1, array $array2) {
270 $array1 = reset($array1);
271 $array2 = reset($array2);
272 if (is_string($array1) && is_string($array2)) {
273 return strcasecmp($array1, $array2);
274 }
275 return 0;
276 }
277
278 }