[TASK] FormEngine: Split TcaTypesShowitem provider
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormDataProvider / TcaTypesShowitem.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\FormDataProvider;
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\Form\FormDataProviderInterface;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\MathUtility;
20
21 /**
22 * Create final showitem configuration in processedTca for types and palette
23 * fields
24 * Handles all the nasty defails like subtypes_addlist and friends.
25 */
26 class TcaTypesShowitem implements FormDataProviderInterface {
27
28 /**
29 * Processed TCA array
30 *
31 * @var array
32 */
33 protected $processedTca;
34
35 /**
36 * Set processedTca showitem
37 *
38 * @param array $result
39 * @return array
40 */
41 public function addData(array $result) {
42 $this->processedTca = $result['processedTca'];
43
44 $recordTypeValue = $result['recordTypeValue'];
45
46 // Inline may override the type value - setting is given down from InlineRecordContainer if so - used primarily for FAL
47 if (!empty($result['overruleTypesArray'][$recordTypeValue]['showitem'])) {
48 $result['processedTca']['types'][$recordTypeValue]['showitem'] = $result['overruleTypesArray'][$recordTypeValue]['showitem'];
49 }
50
51 // Handle subtype_value_field, subtypes_addlist, subtypes_excludelist
52 if (!empty($result['processedTca']['types'][$recordTypeValue]['subtype_value_field'])) {
53 $subtypeFieldName = $result['processedTca']['types'][$recordTypeValue]['subtype_value_field'];
54 if (array_key_exists($subtypeFieldName, $result['databaseRow'])) {
55 $subtypeValue = $result['databaseRow'][$subtypeFieldName];
56 $result = $this->addFieldsBySubtypeAddList($result, $subtypeFieldName, $subtypeValue, $recordTypeValue);
57 $result = $this->removeFieldsBySubtypeExcludeList($result, $subtypeValue, $recordTypeValue);
58 }
59 }
60
61 // Handle bitmask_value_field, bitmask_excludelist_bits
62 if (!empty($result['processedTca']['types'][$recordTypeValue]['bitmask_value_field'])
63 && isset($result['processedTca']['types'][$recordTypeValue]['bitmask_excludelist_bits'])
64 && is_array($result['processedTca']['types'][$recordTypeValue]['bitmask_excludelist_bits'])
65 ) {
66 $bitmaskFieldName = $result['processedTca']['types'][$recordTypeValue]['bitmask_value_field'];
67 if (array_key_exists($bitmaskFieldName, $result['databaseRow'])) {
68 $bitmaskValue = $result['databaseRow'][$bitmaskFieldName];
69 $result = $this->removeFieldsByBitmaskExcludeBits($result, $bitmaskValue, $recordTypeValue);
70 }
71 }
72
73 // Handling of these parameters is finished. Unset them to not allow other handlers to fiddle with it.
74 // unset does not throw notice, even if not set
75 unset($result['processedTca']['types'][$recordTypeValue]['subtype_value_field']);
76 unset($result['processedTca']['types'][$recordTypeValue]['subtypes_excludelist']);
77 unset($result['processedTca']['types'][$recordTypeValue]['subtypes_addlist']);
78 unset($result['processedTca']['types'][$recordTypeValue]['bitmask_value_field']);
79 unset($result['processedTca']['types'][$recordTypeValue]['bitmask_excludelist_bits']);
80
81 return $result;
82 }
83
84 /**
85 * Insert additional fields in showitem based on subtypes_addlist
86 *
87 * databaseRow['theSubtypeValueField'] = 'theSubtypeValue'
88 * showitem = 'foo,theSubtypeValueField,bar'
89 * subtype_value_field = 'theSubtypeValueField'
90 * subtypes_addlist['theSubtypeValue'] = 'additionalField'
91 *
92 * -> showitem = 'foo,theSubtypeValueField,additionalField,bar'
93 *
94 * @param array $result Result array
95 * @param string $subtypeFieldName Field name holding subtype value
96 * @param string $subtypeValue subtype value
97 * @param string $recordTypeValue Given record type value
98 * @return array Modified result array
99 */
100 protected function addFieldsBySubtypeAddList(array $result, $subtypeFieldName, $subtypeValue, $recordTypeValue) {
101 if (!empty($this->processedTca['types'][$recordTypeValue]['subtypes_addlist'][$subtypeValue])
102 && is_string($this->processedTca['types'][$recordTypeValue]['subtypes_addlist'][$subtypeValue])
103 ) {
104 $addListString = $this->processedTca['types'][$recordTypeValue]['subtypes_addlist'][$subtypeValue];
105 $addListArray = GeneralUtility::trimExplode(',', $addListString, TRUE);
106 $showItemFieldString = $result['processedTca']['types'][$recordTypeValue]['showitem'];
107 $showItemFieldArray = GeneralUtility::trimExplode(',', $showItemFieldString, TRUE);
108 // The "new" fields should be added after the subtype field itself, so find it
109 foreach ($showItemFieldArray as $index => $fieldConfigurationString) {
110 $found = FALSE;
111 $fieldConfigurationArray = GeneralUtility::trimExplode(';', $fieldConfigurationString);
112 $fieldName = $fieldConfigurationArray[0];
113 if ($fieldName === $subtypeFieldName) {
114 // Found the subtype value field in showitem
115 $found = TRUE;
116 } elseif ($fieldName === '--palette--') {
117 // Try to find subtype value field in palette
118 if (isset($fieldConfigurationArray[2])) {
119 $paletteName = $fieldConfigurationArray[2];
120 if (!empty($this->processedTca['palettes'][$paletteName]['showitem'])) {
121 $paletteFields = GeneralUtility::trimExplode(',', $this->processedTca['palettes'][$paletteName]['showitem'], TRUE);
122 foreach ($paletteFields as $paletteFieldConfiguration) {
123 $paletteFieldConfigurationArray = GeneralUtility::trimExplode(';', $paletteFieldConfiguration);
124 if ($paletteFieldConfigurationArray[0] === $subtypeFieldName) {
125 // Found it in palette
126 $found = TRUE;
127 break;
128 }
129 }
130 }
131 }
132 }
133 if ($found) {
134 // Add fields between subtype field and next element
135 array_splice($showItemFieldArray, $index + 1, 0, $addListArray);
136 break;
137 }
138 }
139 $result['processedTca']['types'][$recordTypeValue]['showitem'] = implode(',', $showItemFieldArray);
140 }
141 return $result;
142 }
143
144 /**
145 * Remove fields from showitem based on subtypes_excludelist
146 *
147 * databaseRow['theSubtypeValueField'] = 'theSubtypeValue'
148 * showitem = 'foo,toRemove,bar'
149 * subtype_value_field = 'theSubtypeValueField'
150 * subtypes_excludelist['theSubtypeValue'] = 'toRemove'
151 *
152 * -> showitem = 'foo,bar'
153 *
154 * @param array $result Result array
155 * @param string $subtypeValue subtype value
156 * @param string $recordTypeValue Given record type value
157 * @return array Modified result array
158 */
159 protected function removeFieldsBySubtypeExcludeList(array $result, $subtypeValue, $recordTypeValue) {
160 if (!empty($this->processedTca['types'][$recordTypeValue]['subtypes_excludelist'][$subtypeValue])
161 && is_string($this->processedTca['types'][$recordTypeValue]['subtypes_excludelist'][$subtypeValue])
162 ) {
163 $removeListString = $this->processedTca['types'][$recordTypeValue]['subtypes_excludelist'][$subtypeValue];
164 $removeListArray = GeneralUtility::trimExplode(',', $removeListString, TRUE);
165 $result = $this->removeFields($result, $removeListArray, $recordTypeValue);
166 $result = $this->removeFieldsFromPalettes($result, $removeListArray);
167 }
168 return $result;
169 }
170
171 /**
172 * Remove fields from showitem based on subtypes_excludelist
173 *
174 * databaseRow['theSubtypeValueField'] = 5 // 1 0 1
175 * showitem = 'foo,toRemoveBy4,bar'
176 * bitmask_value_field = 'theSubtypeValueField'
177 * bitmask_excludelist_bits[+2] = 'toRemoveBy4'
178 *
179 * -> showitem = 'foo,bar'
180 *
181 * @param array $result Result array
182 * @param string $bitmaskValue subtype value
183 * @param string $recordTypeValue Given record type value
184 * @return array Modified result array
185 */
186 protected function removeFieldsByBitmaskExcludeBits(array $result, $bitmaskValue, $recordTypeValue) {
187 $removeListArray = array();
188 $bitmaskValue = MathUtility::forceIntegerInRange($bitmaskValue, 0);
189 $excludeListBitsArray = $this->processedTca['types'][$recordTypeValue]['bitmask_excludelist_bits'];
190 foreach ($excludeListBitsArray as $bitKey => $excludeList) {
191 $bitKey = (int)$bitKey;
192 $isNegative = (bool)($bitKey < 0);
193 $bit = abs($bitKey);
194 if (!$isNegative && ($bitmaskValue & pow(2, $bit))
195 || $isNegative && !($bitmaskValue & pow(2, $bit))
196 ) {
197 $removeListArray = array_merge($removeListArray, GeneralUtility::trimExplode(',', $excludeList, TRUE));
198 }
199 }
200 $result = $this->removeFields($result, $removeListArray, $recordTypeValue);
201 return $this->removeFieldsFromPalettes($result, $removeListArray);
202 }
203
204 /**
205 * Remove fields from show item field list
206 *
207 * @param array $result Given show item list
208 * @param array $removeListArray Fields to remove
209 * @param string $recordTypeValue Given record type value
210 * @return array Modified result array
211 */
212 protected function removeFields(array $result, array $removeListArray, $recordTypeValue) {
213 $newFieldList = array();
214 $showItemFieldString = $result['processedTca']['types'][$recordTypeValue]['showitem'];
215 $showItemFieldArray = GeneralUtility::trimExplode(',', $showItemFieldString, TRUE);
216 foreach ($showItemFieldArray as $fieldConfigurationString) {
217 $fieldConfigurationArray = GeneralUtility::trimExplode(';', $fieldConfigurationString);
218 $fieldName = $fieldConfigurationArray[0];
219 if (!in_array($fieldConfigurationArray[0], $removeListArray, TRUE)
220 // It does not make sense to exclude --palette-- and --div--
221 || $fieldName === '--palette--' || $fieldName === '--div--'
222 ) {
223 $newFieldList[] = $fieldConfigurationString;
224 }
225 }
226 $result['processedTca']['types'][$recordTypeValue]['showitem'] = implode(',', $newFieldList);
227 return $result;
228 }
229
230 /**
231 * Remove a list of element from all palettes
232 *
233 * @param array $result Result array
234 * @param array $removeListArray Array of elements to remove
235 * @return array Modified result array
236 * @todo: unit tests!
237 */
238 protected function removeFieldsFromPalettes(array $result, $removeListArray) {
239 if (isset($result['processedTca']['palettes']) && is_array($result['processedTca']['palettes'])) {
240 foreach ($result['processedTca']['palettes'] as $paletteName => $paletteArray) {
241 if (!isset($paletteArray['showitem']) || !is_string($paletteArray['showitem'])) {
242 throw new \UnexpectedValueException(
243 'showitem field of palette ' . $paletteName . ' in table ' . $result['tableName'] . ' not found or not a string',
244 1439925240
245 );
246 }
247 $showItemFieldString = $paletteArray['showitem'];
248 $showItemFieldArray = GeneralUtility::trimExplode(',', $showItemFieldString, TRUE);
249 $newFieldList = array();
250 foreach ($showItemFieldArray as $fieldConfigurationString) {
251 $fieldConfigurationArray = GeneralUtility::trimExplode(';', $fieldConfigurationString);
252 $fieldName = $fieldConfigurationArray[0];
253 if (!in_array($fieldConfigurationArray[0], $removeListArray, TRUE)
254 || $fieldName === '--linebreak--'
255 ) {
256 $newFieldList[] = $fieldConfigurationString;
257 }
258 }
259 $result['processedTca']['palettes'][$paletteName]['showitem'] = implode(',', $newFieldList);
260 }
261 }
262 return $result;
263 }
264
265 }