[!!!][TASK] Drop additional palette handling
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Migrations / TcaMigration.php
1 <?php
2 namespace TYPO3\CMS\Core\Migrations;
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 * Migrate TCA from old to new syntax. Used in bootstrap and Flex Form Data Structures.
21 *
22 * @internal Class and API may change any time.
23 */
24 class TcaMigration {
25
26 /**
27 * Accumulate migration messages
28 *
29 * @var array
30 */
31 protected $messages = array();
32
33 /**
34 * Migrate old TCA to new TCA.
35 *
36 * See unit tests for details.
37 *
38 * @param array $tca
39 * @return array
40 */
41 public function migrate(array $tca) {
42 $tca = $this->migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig($tca);
43 $tca = $this->migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig($tca);
44 $tca = $this->migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides($tca);
45 $tca = $this->migrateShowItemAdditionalPaletteToOwnPalette($tca);
46 // @todo: if showitem/defaultExtras wizards[xy] is migrated to columnsOverrides here, enableByTypeConfig could be dropped
47 return $tca;
48 }
49
50 /**
51 * Get messages of migrated fields. Can be used for deprecation messages after migrate() was called.
52 *
53 * @return array Migration messages
54 */
55 public function getMessages() {
56 return $this->messages;
57 }
58
59 /**
60 * Migrate type=text field with t3editor wizard to renderType=t3editor without this wizard
61 *
62 * @param array $tca Incoming TCA
63 * @return array Migrated TCA
64 */
65 protected function migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig(array $tca) {
66 $newTca = $tca;
67 foreach ($tca as $table => $tableDefinition) {
68 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
69 continue;
70 }
71 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
72 if (
73 !empty($fieldConfig['config']['type']) // type is set
74 && trim($fieldConfig['config']['type']) === 'text' // to "text"
75 && isset($fieldConfig['config']['wizards'])
76 && is_array($fieldConfig['config']['wizards']) // and there are wizards
77 ) {
78 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
79 if (
80 !empty($wizardConfig['userFunc']) // a userFunc is defined
81 && trim($wizardConfig['userFunc']) === 'TYPO3\\CMS\\T3editor\\FormWizard->main' // and set to FormWizard
82 && (
83 !isset($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is not set
84 || (isset($wizardConfig['enableByTypeConfig']) && !$wizardConfig['enableByTypeConfig']) // or set, but not enabled
85 )
86 ) {
87 // Set renderType from text to t3editor
88 $newTca[$table]['columns'][$fieldName]['config']['renderType'] = 't3editor';
89 // Unset this wizard definition
90 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
91 // Move format parameter
92 if (!empty($wizardConfig['params']['format'])) {
93 $newTca[$table]['columns'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
94 }
95 $this->messages[] = 'Migrated t3editor wizard in TCA of table "' . $table . '" field "' . $fieldName . '" to a renderType definition.';
96 }
97 }
98 // If no wizard is left after migration, unset the whole sub array
99 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
100 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
101 }
102 }
103 }
104 }
105 return $newTca;
106 }
107
108 /**
109 * Remove "style pointer", the 5th parameter from "types" "showitem" configuration.
110 * Move "specConf", 4th parameter from "tyes" "showitem" to "types" "columnsOverrides.
111 *
112 * @param array $tca Incoming TCA
113 * @return array Modified TCA
114 */
115 protected function migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig(array $tca) {
116 $newTca = $tca;
117 foreach ($tca as $table => $tableDefinition) {
118 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
119 continue;
120 }
121 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
122 if (!is_string($typeArray['showitem']) || strpos($typeArray['showitem'], ';') === FALSE) {
123 // Continue directly if no semicolon is found
124 continue;
125 }
126 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], TRUE);
127 $newFieldStrings = array();
128 foreach ($itemList as $fieldString) {
129 $fieldString = rtrim($fieldString, ';');
130 // Unpack the field definition, migrate and remove as much as possible
131 // Keep empty parameters in trimExplode here (third parameter FALSE), so position is not changed
132 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
133 $fieldArray = array(
134 'fieldName' => isset($fieldArray[0]) ? $fieldArray[0] : '',
135 'fieldLabel' => isset($fieldArray[1]) ? $fieldArray[1] : NULL,
136 'paletteName' => isset($fieldArray[2]) ? $fieldArray[2] : NULL,
137 'fieldExtra' => isset($fieldArray[3]) ? $fieldArray[3] : NULL,
138 );
139 $fieldName = $fieldArray['fieldName'];
140 if (!empty($fieldArray['fieldExtra'])) {
141 // Move fieldExtra "specConf" to columnsOverrides "defaultExtras"
142 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'])) {
143 $newTca[$table]['types'][$typeName]['columnsOverrides'] = array();
144 }
145 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']])) {
146 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']] = array();
147 }
148 // Merge with given defaultExtras from columns.
149 // They will be the first part of the string, so if "specConf" from types changes the same settings,
150 // those will override settings from defaultExtras of columns
151 $newDefaultExtras = array();
152 if (!empty($tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'])) {
153 $newDefaultExtras[] = $tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'];
154 }
155 $newDefaultExtras[] = $fieldArray['fieldExtra'];
156 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']]['defaultExtras'] = implode(':', $newDefaultExtras);
157 }
158 unset($fieldArray['fieldExtra']);
159 if (count($fieldArray) === 3 && empty($fieldArray['paletteName'])) {
160 unset($fieldArray['paletteName']);
161 }
162 if (count($fieldArray) === 2 && empty($fieldArray['fieldLabel'])) {
163 unset($fieldArray['fieldLabel']);
164 }
165 if (count($fieldArray) === 1 && empty($fieldArray['fieldName'])) {
166 // The field may vanish if nothing is left
167 unset($fieldArray['fieldName']);
168 }
169 $newFieldString = implode(';', $fieldArray);
170 if ($newFieldString !== $fieldString) {
171 $this->messages[] = 'Changed showitem string of TCA table "' . $table . '" type "' . $typeName . '" due to changed field "' . $fieldName . '".';
172 }
173 if (!empty($newFieldString)) {
174 $newFieldStrings[] = $newFieldString;
175 }
176 }
177 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
178 }
179 }
180 return $newTca;
181 }
182
183 /**
184 * Migrate type=text field with t3editor wizard that is "enableByTypeConfig" to columnsOverrides
185 * with renderType=t3editor
186 *
187 * @param array $tca Incoming TCA
188 * @return array Migrated TCA
189 */
190 protected function migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides(array $tca) {
191 $newTca = $tca;
192 foreach ($tca as $table => $tableDefinition) {
193 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
194 continue;
195 }
196 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
197 if (
198 !empty($fieldConfig['config']['type']) // type is set
199 && trim($fieldConfig['config']['type']) === 'text' // to "text"
200 && isset($fieldConfig['config']['wizards'])
201 && is_array($fieldConfig['config']['wizards']) // and there are wizards
202 ) {
203 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
204 if (
205 !empty($wizardConfig['userFunc']) // a userFunc is defined
206 && trim($wizardConfig['userFunc']) === 'TYPO3\CMS\T3editor\FormWizard->main' // and set to FormWizard
207 && !empty($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is enabled
208 ) {
209 // Remove this wizard
210 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
211 // Find configured types that use this wizard
212 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
213 // No type definition at all ... continue directly
214 continue;
215 }
216 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
217 if (
218 empty($typeArray['columnsOverrides'][$fieldName]['defaultExtras'])
219 || strpos($typeArray['columnsOverrides'][$fieldName]['defaultExtras'], $wizardName) === FALSE
220 ) {
221 // Continue directly if this wizard is not enabled for given type
222 continue;
223 }
224 $defaultExtras = $typeArray['columnsOverrides'][$fieldName]['defaultExtras'];
225 $defaultExtrasArray = GeneralUtility::trimExplode(':', $defaultExtras, TRUE);
226 $newDefaultExtrasArray = array();
227 foreach ($defaultExtrasArray as $fieldExtraField) {
228 // There might be multiple enabled wizards separated by | ... split them
229 if (substr($fieldExtraField, 0, 8) === 'wizards[') {
230 $enabledWizards = substr($fieldExtraField, 8, strlen($fieldExtraField) - 8); // Cut off "wizards[
231 $enabledWizards = substr($enabledWizards, 0, strlen($enabledWizards) - 1);
232 $enabledWizardsArray = GeneralUtility::trimExplode('|', $enabledWizards, TRUE);
233 $newEnabledWizardsArray = array();
234 foreach ($enabledWizardsArray as $enabledWizardName) {
235 if ($enabledWizardName === $wizardName) {
236 // Found a columnsOverrides configuration that has this wizard enabled
237 // Force renderType = t3editor
238 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['renderType'] = 't3editor';
239 // Transfer format option if given
240 if (!empty($wizardConfig['params']['format'])) {
241 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
242 }
243 $this->messages[] = 'Migrated t3editor wizard in TCA of table "' . $table . '" field "' . $fieldName
244 . '" to a renderType definition with columnsOverrides in type "' . $typeName . '".';
245 } else {
246 // Some other enabled wizard
247 $newEnabledWizardsArray[] = $enabledWizardName;
248 }
249 }
250 if (!empty($newEnabledWizardsArray)) {
251 $newDefaultExtrasArray[] = 'wizards[' . implode('|', $newEnabledWizardsArray) . ']';
252 }
253 } else {
254 $newDefaultExtrasArray[] = $fieldExtraField;
255 }
256 }
257 if (!empty($newDefaultExtrasArray)) {
258 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras'] = implode(':', $newDefaultExtrasArray);
259 } else {
260 unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras']);
261 }
262 }
263 }
264 }
265 // If no wizard is left after migration, unset the whole sub array
266 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
267 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
268 }
269 }
270 }
271 }
272 return $newTca;
273 }
274
275 /**
276 * Migrate types showitem 'aField;aLabel;aPalette' to 'afield;aLabel, --palette--;;aPalette'
277 *
278 * Old showitem can have a syntax like:
279 * fieldName;aLabel;aPalette
280 * This way, the palette with name "aPalette" is rendered after fieldName.
281 * The migration parses this to a syntax like:
282 * fieldName;aLabel, --palette--;;paletteName
283 *
284 * @param array $tca Incoming TCA
285 * @return array Migrated TCA
286 */
287 protected function migrateShowItemAdditionalPaletteToOwnPalette(array $tca) {
288 $newTca = $tca;
289 foreach ($tca as $table => $tableDefinition) {
290 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
291 continue;
292 }
293 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
294 if (
295 !isset($typeArray['showitem'])
296 || !is_string($typeArray['showitem'])
297 || strpos($typeArray['showitem'], ';') === FALSE // no field parameters
298 ) {
299 continue;
300 }
301 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], TRUE);
302 $newFieldStrings = array();
303 foreach ($itemList as $fieldString) {
304 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
305 $fieldArray = array(
306 'fieldName' => isset($fieldArray[0]) ? $fieldArray[0] : '',
307 'fieldLabel' => isset($fieldArray[1]) ? $fieldArray[1] : NULL,
308 'paletteName' => isset($fieldArray[2]) ? $fieldArray[2] : NULL,
309 );
310 if ($fieldArray['fieldName'] !== '--palette--' && $fieldArray['paletteName'] !== NULL) {
311 if ($fieldArray['fieldLabel']) {
312 $fieldString = $fieldArray['fieldName'] . ';' . $fieldArray['fieldLabel'];
313 } else {
314 $fieldString = $fieldArray['fieldName'];
315 }
316 $paletteString = '--palette--;;' . $fieldArray['paletteName'];
317 $this->messages[] = 'Migrated TCA table "' . $table . '" showitem field of type "' . $typeName . '": Moved additional palette'
318 . ' with name "' . $fieldArray['paletteName'] . '" as 3rd argument of field "' . $fieldArray['fieldName']
319 . '" to an own palette. The result of this part is: "' . $fieldString . ', ' . $paletteString . '"';
320 $newFieldStrings[] = $fieldString;
321 $newFieldStrings[] = $paletteString;
322 } else {
323 $newFieldStrings[] = $fieldString;
324 }
325 }
326 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
327 }
328 }
329 return $newTca;
330 }
331 }