[!!!][TASK] Improve flex and TCA handling in FormEngine
[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 = [];
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 {
43 $tca = $this->migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig($tca);
44 $tca = $this->migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig($tca);
45 $tca = $this->migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides($tca);
46 $tca = $this->migrateShowItemAdditionalPaletteToOwnPalette($tca);
47 $tca = $this->migrateIconsForFormFieldWizardsToNewLocation($tca);
48 $tca = $this->migrateExtAndSysextPathToEXTPath($tca);
49 $tca = $this->migrateIconsInOptionTags($tca);
50 $tca = $this->migrateIconfileRelativePathOrFilenameOnlyToExtReference($tca);
51 $tca = $this->migrateSelectFieldRenderType($tca);
52 $tca = $this->migrateSelectFieldIconTable($tca);
53 $tca = $this->migrateElementBrowserWizardToLinkHandler($tca);
54 $tca = $this->migrateDefaultExtrasRteTransFormOptions($tca);
55 $tca = $this->migrateColorPickerWizardToRenderType($tca);
56 $tca = $this->migrateSelectTreeOptions($tca);
57 $tca = $this->migrateTSconfigSoftReferences($tca);
58 $tca = $this->migrateShowIfRteOption($tca);
59 $tca = $this->migrateWorkspacesOptions($tca);
60 $tca = $this->migrateTranslationTable($tca);
61 $tca = $this->migrateRequestUpdate($tca);
62 // @todo: if showitem/defaultExtras wizards[xy] is migrated to columnsOverrides here, enableByTypeConfig could be dropped
63 return $tca;
64 }
65
66 /**
67 * Get messages of migrated fields. Can be used for deprecation messages after migrate() was called.
68 *
69 * @return array Migration messages
70 */
71 public function getMessages()
72 {
73 return $this->messages;
74 }
75
76 /**
77 * Migrate type=text field with t3editor wizard to renderType=t3editor without this wizard
78 *
79 * @param array $tca Incoming TCA
80 * @return array Migrated TCA
81 */
82 protected function migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig(array $tca)
83 {
84 $newTca = $tca;
85 foreach ($tca as $table => $tableDefinition) {
86 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
87 continue;
88 }
89 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
90 if (
91 !empty($fieldConfig['config']['type']) // type is set
92 && trim($fieldConfig['config']['type']) === 'text' // to "text"
93 && isset($fieldConfig['config']['wizards'])
94 && is_array($fieldConfig['config']['wizards']) // and there are wizards
95 ) {
96 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
97 if (
98 !empty($wizardConfig['userFunc']) // a userFunc is defined
99 && trim($wizardConfig['userFunc']) === 'TYPO3\\CMS\\T3editor\\FormWizard->main' // and set to FormWizard
100 && (
101 !isset($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is not set
102 || (isset($wizardConfig['enableByTypeConfig']) && !$wizardConfig['enableByTypeConfig']) // or set, but not enabled
103 )
104 ) {
105 // Set renderType from text to t3editor
106 $newTca[$table]['columns'][$fieldName]['config']['renderType'] = 't3editor';
107 // Unset this wizard definition
108 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
109 // Move format parameter
110 if (!empty($wizardConfig['params']['format'])) {
111 $newTca[$table]['columns'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
112 }
113 $this->messages[] = 'Migrated t3editor wizard in TCA of table "' . $table . '" field "' . $fieldName . '" to a renderType definition.';
114 }
115 }
116 // If no wizard is left after migration, unset the whole sub array
117 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
118 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
119 }
120 }
121 }
122 }
123 return $newTca;
124 }
125
126 /**
127 * Remove "style pointer", the 5th parameter from "types" "showitem" configuration.
128 * Move "specConf", 4th parameter from "tyes" "showitem" to "types" "columnsOverrides.
129 *
130 * @param array $tca Incoming TCA
131 * @return array Modified TCA
132 */
133 protected function migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig(array $tca)
134 {
135 $newTca = $tca;
136 foreach ($tca as $table => $tableDefinition) {
137 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
138 continue;
139 }
140 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
141 if (!isset($typeArray['showitem']) || !is_string($typeArray['showitem']) || strpos($typeArray['showitem'], ';') === false) {
142 // Continue directly if no semicolon is found
143 continue;
144 }
145 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], true);
146 $newFieldStrings = [];
147 foreach ($itemList as $fieldString) {
148 $fieldString = rtrim($fieldString, ';');
149 // Unpack the field definition, migrate and remove as much as possible
150 // Keep empty parameters in trimExplode here (third parameter FALSE), so position is not changed
151 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
152 $fieldArray = [
153 'fieldName' => isset($fieldArray[0]) ? $fieldArray[0] : '',
154 'fieldLabel' => isset($fieldArray[1]) ? $fieldArray[1] : null,
155 'paletteName' => isset($fieldArray[2]) ? $fieldArray[2] : null,
156 'fieldExtra' => isset($fieldArray[3]) ? $fieldArray[3] : null,
157 ];
158 $fieldName = $fieldArray['fieldName'];
159 if (!empty($fieldArray['fieldExtra'])) {
160 // Move fieldExtra "specConf" to columnsOverrides "defaultExtras"
161 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'])) {
162 $newTca[$table]['types'][$typeName]['columnsOverrides'] = [];
163 }
164 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']])) {
165 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']] = [];
166 }
167 // Merge with given defaultExtras from columns.
168 // They will be the first part of the string, so if "specConf" from types changes the same settings,
169 // those will override settings from defaultExtras of columns
170 $newDefaultExtras = [];
171 if (!empty($tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'])) {
172 $newDefaultExtras[] = $tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'];
173 }
174 $newDefaultExtras[] = $fieldArray['fieldExtra'];
175 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']]['defaultExtras'] = implode(':', $newDefaultExtras);
176 }
177 unset($fieldArray['fieldExtra']);
178 if (count($fieldArray) === 3 && empty($fieldArray['paletteName'])) {
179 unset($fieldArray['paletteName']);
180 }
181 if (count($fieldArray) === 2 && empty($fieldArray['fieldLabel'])) {
182 unset($fieldArray['fieldLabel']);
183 }
184 if (count($fieldArray) === 1 && empty($fieldArray['fieldName'])) {
185 // The field may vanish if nothing is left
186 unset($fieldArray['fieldName']);
187 }
188 $newFieldString = implode(';', $fieldArray);
189 if ($newFieldString !== $fieldString) {
190 $this->messages[] = 'Changed showitem string of TCA table "' . $table . '" type "' . $typeName . '" due to changed field "' . $fieldName . '".';
191 }
192 if (!empty($newFieldString)) {
193 $newFieldStrings[] = $newFieldString;
194 }
195 }
196 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
197 }
198 }
199 return $newTca;
200 }
201
202 /**
203 * Migrate type=text field with t3editor wizard that is "enableByTypeConfig" to columnsOverrides
204 * with renderType=t3editor
205 *
206 * @param array $tca Incoming TCA
207 * @return array Migrated TCA
208 */
209 protected function migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides(array $tca)
210 {
211 $newTca = $tca;
212 foreach ($tca as $table => $tableDefinition) {
213 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
214 continue;
215 }
216 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
217 if (
218 !empty($fieldConfig['config']['type']) // type is set
219 && trim($fieldConfig['config']['type']) === 'text' // to "text"
220 && isset($fieldConfig['config']['wizards'])
221 && is_array($fieldConfig['config']['wizards']) // and there are wizards
222 ) {
223 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
224 if (
225 !empty($wizardConfig['userFunc']) // a userFunc is defined
226 && trim($wizardConfig['userFunc']) === 'TYPO3\CMS\T3editor\FormWizard->main' // and set to FormWizard
227 && !empty($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is enabled
228 ) {
229 // Remove this wizard
230 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
231 // Find configured types that use this wizard
232 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
233 // No type definition at all ... continue directly
234 continue;
235 }
236 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
237 if (
238 empty($typeArray['columnsOverrides'][$fieldName]['defaultExtras'])
239 || strpos($typeArray['columnsOverrides'][$fieldName]['defaultExtras'], $wizardName) === false
240 ) {
241 // Continue directly if this wizard is not enabled for given type
242 continue;
243 }
244 $defaultExtras = $typeArray['columnsOverrides'][$fieldName]['defaultExtras'];
245 $defaultExtrasArray = GeneralUtility::trimExplode(':', $defaultExtras, true);
246 $newDefaultExtrasArray = [];
247 foreach ($defaultExtrasArray as $fieldExtraField) {
248 // There might be multiple enabled wizards separated by | ... split them
249 if (substr($fieldExtraField, 0, 8) === 'wizards[') {
250 $enabledWizards = substr($fieldExtraField, 8, strlen($fieldExtraField) - 8); // Cut off "wizards[
251 $enabledWizards = substr($enabledWizards, 0, strlen($enabledWizards) - 1);
252 $enabledWizardsArray = GeneralUtility::trimExplode('|', $enabledWizards, true);
253 $newEnabledWizardsArray = [];
254 foreach ($enabledWizardsArray as $enabledWizardName) {
255 if ($enabledWizardName === $wizardName) {
256 // Found a columnsOverrides configuration that has this wizard enabled
257 // Force renderType = t3editor
258 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['renderType'] = 't3editor';
259 // Transfer format option if given
260 if (!empty($wizardConfig['params']['format'])) {
261 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
262 }
263 $this->messages[] = 'Migrated t3editor wizard in TCA of table "' . $table . '" field "' . $fieldName
264 . '" to a renderType definition with columnsOverrides in type "' . $typeName . '".';
265 } else {
266 // Some other enabled wizard
267 $newEnabledWizardsArray[] = $enabledWizardName;
268 }
269 }
270 if (!empty($newEnabledWizardsArray)) {
271 $newDefaultExtrasArray[] = 'wizards[' . implode('|', $newEnabledWizardsArray) . ']';
272 }
273 } else {
274 $newDefaultExtrasArray[] = $fieldExtraField;
275 }
276 }
277 if (!empty($newDefaultExtrasArray)) {
278 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras'] = implode(':', $newDefaultExtrasArray);
279 } else {
280 unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras']);
281 }
282 }
283 }
284 }
285 // If no wizard is left after migration, unset the whole sub array
286 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
287 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
288 }
289 }
290 }
291 }
292 return $newTca;
293 }
294
295 /**
296 * Migrate types showitem 'aField;aLabel;aPalette' to 'afield;aLabel, --palette--;;aPalette'
297 *
298 * Old showitem can have a syntax like:
299 * fieldName;aLabel;aPalette
300 * This way, the palette with name "aPalette" is rendered after fieldName.
301 * The migration parses this to a syntax like:
302 * fieldName;aLabel, --palette--;;paletteName
303 *
304 * @param array $tca Incoming TCA
305 * @return array Migrated TCA
306 */
307 protected function migrateShowItemAdditionalPaletteToOwnPalette(array $tca)
308 {
309 $newTca = $tca;
310 foreach ($tca as $table => $tableDefinition) {
311 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
312 continue;
313 }
314 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
315 if (
316 !isset($typeArray['showitem'])
317 || !is_string($typeArray['showitem'])
318 || strpos($typeArray['showitem'], ';') === false // no field parameters
319 ) {
320 continue;
321 }
322 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], true);
323 $newFieldStrings = [];
324 foreach ($itemList as $fieldString) {
325 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
326 $fieldArray = [
327 'fieldName' => isset($fieldArray[0]) ? $fieldArray[0] : '',
328 'fieldLabel' => isset($fieldArray[1]) ? $fieldArray[1] : null,
329 'paletteName' => isset($fieldArray[2]) ? $fieldArray[2] : null,
330 ];
331 if ($fieldArray['fieldName'] !== '--palette--' && $fieldArray['paletteName'] !== null) {
332 if ($fieldArray['fieldLabel']) {
333 $fieldString = $fieldArray['fieldName'] . ';' . $fieldArray['fieldLabel'];
334 } else {
335 $fieldString = $fieldArray['fieldName'];
336 }
337 $paletteString = '--palette--;;' . $fieldArray['paletteName'];
338 $this->messages[] = 'Migrated TCA table "' . $table . '" showitem field of type "' . $typeName . '": Moved additional palette'
339 . ' with name "' . $fieldArray['paletteName'] . '" as 3rd argument of field "' . $fieldArray['fieldName']
340 . '" to an own palette. The result of this part is: "' . $fieldString . ', ' . $paletteString . '"';
341 $newFieldStrings[] = $fieldString;
342 $newFieldStrings[] = $paletteString;
343 } else {
344 $newFieldStrings[] = $fieldString;
345 }
346 }
347 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
348 }
349 }
350 return $newTca;
351 }
352
353 /**
354 * Migrate core icons for form field wizard to new location
355 *
356 * @param array $tca Incoming TCA
357 * @return array Migrated TCA
358 */
359 protected function migrateIconsForFormFieldWizardsToNewLocation(array $tca)
360 {
361 $newTca = $tca;
362
363 $newFileLocations = [
364 'add.gif' => 'actions-add',
365 'link_popup.gif' => 'actions-wizard-link',
366 'wizard_rte2.gif' => 'actions-wizard-rte',
367 'wizard_table.gif' => 'content-table',
368 'edit2.gif' => 'actions-open',
369 'list.gif' => 'actions-system-list-open',
370 'wizard_forms.gif' => 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_forms.gif',
371 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_add.gif' => 'actions-add',
372 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_table.gif' => 'content-table',
373 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_edit.gif' => 'actions-open',
374 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_list.gif' => 'actions-system-list-open',
375 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_link.gif' => 'actions-wizard-link',
376 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_rte.gif' => 'actions-wizard-rte'
377 ];
378 $oldFileNames = array_keys($newFileLocations);
379
380 foreach ($tca as $table => $tableDefinition) {
381 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
382 continue;
383 }
384 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
385 if (
386 isset($fieldConfig['config']['wizards'])
387 && is_array($fieldConfig['config']['wizards']) // and there are wizards
388 ) {
389 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
390 if (!is_array($wizardConfig)) {
391 continue;
392 }
393
394 foreach ($wizardConfig as $option => $value) {
395 if ($option === 'icon' && in_array($value, $oldFileNames, true)) {
396 $newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]['icon'] = $newFileLocations[$value];
397 $this->messages[] = 'Migrated icon path of wizard "' . $wizardName . '" in field "' . $fieldName . '" from TCA table "' . $table . '". New path is: ' . $newFileLocations[$value];
398 }
399 }
400 }
401 }
402 }
403 }
404
405 return $newTca;
406 }
407
408 /**
409 * Migrate file reference which starts with ext/ or sysext/ to EXT:
410 *
411 * @param array $tca Incoming TCA
412 * @return array Migrated TCA
413 */
414 protected function migrateExtAndSysextPathToEXTPath(array $tca)
415 {
416 foreach ($tca as $table => &$tableDefinition) {
417 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
418 continue;
419 }
420 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
421 if (
422 !empty($fieldConfig['config']['type']) // type is set
423 && trim($fieldConfig['config']['type']) === 'select' // to "select"
424 && isset($fieldConfig['config']['items'])
425 && is_array($fieldConfig['config']['items']) // and there are items
426 ) {
427 foreach ($fieldConfig['config']['items'] as &$itemConfig) {
428 // more then two values? then the third entry is the image path
429 if (!empty($itemConfig[2])) {
430 $tcaPath = implode('.', [$table, 'columns', $fieldName, 'config', 'items']);
431 $pathParts = GeneralUtility::trimExplode('/', $itemConfig[2]);
432 // remove first element (ext or sysext)
433 array_shift($pathParts);
434 $path = implode('/', $pathParts);
435 // If the path starts with ext/ or sysext/ migrate it
436 if (
437 strpos($itemConfig[2], 'ext/') === 0
438 || strpos($itemConfig[2], 'sysext/') === 0
439 ) {
440 $this->messages[] = '[' . $tcaPath . '] ext/ or sysext/ within the path (' . $path . ') in items array is deprecated, use EXT: reference';
441 $itemConfig[2] = 'EXT:' . $path;
442 } elseif (strpos($itemConfig[2], 'i/') === 0) {
443 $this->messages[] = '[' . $tcaPath . '] i/ within the path (' . $path . ') in items array is deprecated, use EXT: reference';
444 $itemConfig[2] = 'EXT:t3skin/icons/gfx/' . $itemConfig[2];
445 }
446 }
447 }
448 }
449 }
450 }
451 return $tca;
452 }
453
454 /**
455 * Migrate "iconsInOptionTags" for "select" TCA fields
456 *
457 * @param array $tca Incoming TCA
458 * @return array Migrated TCA
459 */
460 protected function migrateIconsInOptionTags(array $tca)
461 {
462 $newTca = $tca;
463
464 foreach ($newTca as $table => &$tableDefinition) {
465 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
466 continue;
467 }
468 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
469 if (isset($fieldConfig['config']['iconsInOptionTags'])) {
470 unset($fieldConfig['config']['iconsInOptionTags']);
471 $this->messages[] = 'Configuration option "iconsInOptionTags" was removed from field "' . $fieldName . '" in TCA table "' . $table . '"';
472 }
473 }
474 }
475
476 return $newTca;
477 }
478
479 /**
480 * Migrate "iconfile" references which starts with ../ to EXT: and consisting of filename only to absolute paths in EXT:t3skin
481 *
482 * @param array $tca Incoming TCA
483 * @return array Migrated TCA
484 */
485 protected function migrateIconfileRelativePathOrFilenameOnlyToExtReference(array $tca)
486 {
487 foreach ($tca as $table => &$tableDefinition) {
488 if (!isset($tableDefinition['ctrl']) || !is_array($tableDefinition['ctrl'])) {
489 continue;
490 }
491 if (!isset($tableDefinition['ctrl']['iconfile'])) {
492 continue;
493 }
494 if (strpos($tableDefinition['ctrl']['iconfile'], '../typo3conf/ext/') === 0) {
495 $tableDefinition['ctrl']['iconfile'] = str_replace('../typo3conf/ext/', 'EXT:', $tableDefinition['ctrl']['iconfile']);
496 $tcaPath = implode('.', [$table, 'ctrl', 'iconfile']);
497 $this->messages[] = '[' . $tcaPath . '] relative path to ../typo3conf/ext/ is deprecated, use EXT: instead';
498 } elseif (strpos($tableDefinition['ctrl']['iconfile'], '/') === false) {
499 $tableDefinition['ctrl']['iconfile'] = 'EXT:t3skin/icons/gfx/i/' . $tableDefinition['ctrl']['iconfile'];
500 $tcaPath = implode('.', [$table, 'ctrl', 'iconfile']);
501 $this->messages[] = '[' . $tcaPath . '] filename only is deprecated, use EXT: or absolute reference instead';
502 }
503 }
504 return $tca;
505 }
506
507 /**
508 * Migrate "type=select" with "renderMode=[tree|singlebox|checkbox]" to "renderType=[selectTree|selectSingleBox|selectCheckBox]".
509 * This migration also take care of "maxitems" settings and set "renderType=[selectSingle|selectMultipleSideBySide]" if no other
510 * renderType is already set.
511 *
512 * @param array $tca
513 * @return array
514 */
515 public function migrateSelectFieldRenderType(array $tca)
516 {
517 $newTca = $tca;
518
519 foreach ($newTca as $table => &$tableDefinition) {
520 if (empty($tableDefinition['columns'])) {
521 continue;
522 }
523
524 foreach ($tableDefinition['columns'] as $columnName => &$columnDefinition) {
525 // Only handle select fields.
526 if (empty($columnDefinition['config']['type']) || $columnDefinition['config']['type'] !== 'select') {
527 continue;
528 }
529 // Do not handle field where the render type is set.
530 if (!empty($columnDefinition['config']['renderType'])) {
531 continue;
532 }
533
534 $tableColumnInfo = 'table "' . $table . '" and column "' . $columnName . '"';
535 $this->messages[] = 'Using select fields without the "renderType" setting is deprecated in ' . $tableColumnInfo;
536
537 $columnConfig = &$columnDefinition['config'];
538 if (!empty($columnConfig['renderMode'])) {
539 $this->messages[] = 'The "renderMode" setting for select fields is deprecated. Please use "renderType" instead in ' . $tableColumnInfo;
540 switch ($columnConfig['renderMode']) {
541 case 'tree':
542 $columnConfig['renderType'] = 'selectTree';
543 break;
544 case 'singlebox':
545 $columnConfig['renderType'] = 'selectSingleBox';
546 break;
547 case 'checkbox':
548 $columnConfig['renderType'] = 'selectCheckBox';
549 break;
550 default:
551 $this->messages[] = 'The render mode ' . $columnConfig['renderMode'] . ' is invalid for the select field in ' . $tableColumnInfo;
552 }
553 continue;
554 }
555
556 $maxItems = !empty($columnConfig['maxitems']) ? (int)$columnConfig['maxitems'] : 1;
557 if ($maxItems <= 1) {
558 $columnConfig['renderType'] = 'selectSingle';
559 } else {
560 $columnConfig['renderType'] = 'selectMultipleSideBySide';
561 }
562 }
563 }
564
565 return $newTca;
566 }
567
568 /**
569 * Migrate the visibility of the icon table for fields with "renderType=selectSingle"
570 *
571 * @param array $tca
572 * @return array Migrated TCA
573 */
574 public function migrateSelectFieldIconTable(array $tca)
575 {
576 foreach ($tca as $table => &$tableDefinition) {
577 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
578 continue;
579 }
580 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
581 if (empty($fieldConfig['config']['renderType']) || $fieldConfig['config']['renderType'] !== 'selectSingle') {
582 continue;
583 }
584 if (!empty($fieldConfig['config']['selicon_cols'])) {
585 // selicon_cols without showIconTable true does not make sense, so set it to true here if not already defined
586 if (!array_key_exists('showIconTable', $fieldConfig['config'])) {
587 $this->messages[] = 'The "showIconTable" setting is missing for table "' . $table . '" and field "' . $fieldName . '"';
588 $fieldConfig['config']['showIconTable'] = true;
589 }
590 }
591 if (array_key_exists('noIconsBelowSelect', $fieldConfig['config'])) {
592 $this->messages[] = 'The "noIconsBelowSelect" setting for select fields was removed. Please define the setting "showIconTable" for table "' . $table . '" and field "' . $fieldName . '"';
593 if (!$fieldConfig['config']['noIconsBelowSelect']) {
594 // If old setting was explicitly false, enable icon table if not defined yet
595 if (!array_key_exists('showIconTable', $fieldConfig['config'])) {
596 $fieldConfig['config']['showIconTable'] = true;
597 }
598 }
599 unset($fieldConfig['config']['noIconsBelowSelect']);
600 }
601 if (array_key_exists('suppress_icons', $fieldConfig['config'])) {
602 $this->messages[] = 'The "suppress_icons" setting for select fields was removed. Please define the setting "showIconTable" for table "' . $table . '" and field "' . $fieldName . '"';
603 unset($fieldConfig['config']['suppress_icons']);
604 }
605 if (array_key_exists('foreign_table_loadIcons', $fieldConfig['config'])) {
606 $this->messages[] = 'The "foreign_table_loadIcons" setting for select fields was removed. Please define the setting "showIconTable" for table "' . $table . '" and field "' . $fieldName . '"';
607 unset($fieldConfig['config']['foreign_table_loadIcons']);
608 }
609 }
610 }
611 return $tca;
612 }
613
614 /**
615 * Migrate wizard "wizard_element_browser" used in mode "wizard" to use the "wizard_link" instead
616 *
617 * @param array $tca
618 * @return array Migrated TCA
619 */
620 protected function migrateElementBrowserWizardToLinkHandler(array $tca)
621 {
622 foreach ($tca as $table => &$tableDefinition) {
623 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
624 continue;
625 }
626 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
627 if (
628 isset($fieldConfig['config']['wizards']['link']['module']['name']) && $fieldConfig['config']['wizards']['link']['module']['name'] === 'wizard_element_browser'
629 && isset($fieldConfig['config']['wizards']['link']['module']['urlParameters']['mode']) && $fieldConfig['config']['wizards']['link']['module']['urlParameters']['mode'] === 'wizard'
630 ) {
631 $fieldConfig['config']['wizards']['link']['module']['name'] = 'wizard_link';
632 unset($fieldConfig['config']['wizards']['link']['module']['urlParameters']['mode']);
633 if (empty($fieldConfig['config']['wizards']['link']['module']['urlParameters'])) {
634 unset($fieldConfig['config']['wizards']['link']['module']['urlParameters']);
635 }
636 $this->messages[] = 'Reference to "wizard_element_browser" was migrated to new "wizard_link" for field "' . $fieldName . '" in TCA table "' . $table . '"';
637 }
638 }
639 }
640 return $tca;
641 }
642
643 /**
644 * Migrate defaultExtras "richtext:rte_transform[mode=ts_css]" and similar stuff like
645 * "richtext:rte_transform[mode=ts_css]" to "richtext:rte_transform"
646 *
647 * @param array $tca
648 * @return array Migrated TCA
649 */
650 protected function migrateDefaultExtrasRteTransFormOptions(array $tca)
651 {
652 foreach ($tca as $table => &$tableDefinition) {
653 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
654 continue;
655 }
656 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
657 if (isset($fieldConfig['defaultExtras'])) {
658 $oldValue = $fieldConfig['defaultExtras'];
659 $fieldConfig['defaultExtras'] = preg_replace(
660 '/richtext(\[([^\]]*)\])*:rte_transform(\[([^\]]*)\])/',
661 'richtext${1}:rte_transform',
662 $fieldConfig['defaultExtras'],
663 -1,
664 $replacementCount
665 );
666 if ($replacementCount) {
667 $this->messages[] = 'rte_transform options are deprecated. String "' . $oldValue . '" in TCA'
668 . ' ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'defaultExtras\'] was changed to "'
669 . $fieldConfig['defaultExtras'] . '"';
670 }
671 }
672 }
673 }
674
675 foreach ($tca as $table => &$tableDefinition) {
676 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
677 continue;
678 }
679 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
680 if (!isset($typeArray['columnsOverrides']) || !is_array($typeArray['columnsOverrides'])) {
681 continue;
682 }
683 foreach ($typeArray['columnsOverrides'] as $fieldName => &$fieldConfig) {
684 if (isset($fieldConfig['defaultExtras'])) {
685 $oldValue = $fieldConfig['defaultExtras'];
686 $fieldConfig['defaultExtras'] = preg_replace(
687 '/richtext(\[([^\]]*)\])*:rte_transform(\[([^\]]*)\])/',
688 'richtext${1}:rte_transform',
689 $fieldConfig['defaultExtras'],
690 -1,
691 $replacementCount
692 );
693 if ($replacementCount) {
694 $this->messages[] = 'rte_transform options are deprecated. String "'
695 . $oldValue . '" in TCA'
696 . ' ' . $table . '[\'types\'][\'' . $typeName
697 . '\'][\'columnsOverrides\'][\'' . $fieldName
698 . '\'][\'defaultExtras\']' .
699 ' was changed to "' . $fieldConfig['defaultExtras'] . '"';
700 }
701 }
702 }
703 }
704 }
705
706 return $tca;
707 }
708
709 /**
710 * Migrates fields having a colorpicker wizard to a color field
711 *
712 * @param array $tca Incoming TCA
713 * @return array Migrated TCA
714 */
715 protected function migrateColorPickerWizardToRenderType(array $tca)
716 {
717 foreach ($tca as $table => &$tableDefinition) {
718 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
719 continue;
720 }
721 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
722 if (isset($fieldConfig['config'])) {
723 if (isset($fieldConfig['config']['wizards'])) {
724 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizard) {
725 if (isset($wizard['type']) && ($wizard['type'] === 'colorbox')) {
726 unset($fieldConfig['config']['wizards'][$wizardName]);
727 if (empty($fieldConfig['config']['wizards'])) {
728 unset($fieldConfig['config']['wizards']);
729 }
730 $fieldConfig['config']['renderType'] = 'colorpicker';
731
732 $this->messages[] = 'The color-picker wizard using \'colorbox\' is deprecated'
733 . ' in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
734 . '[\'wizards\'][\'' . $wizardName . '\'] and is changed to ' . $table
735 . '[\'columns\'][\'' . $fieldName . '\'][\'config\'] = \'colorpicker\'';
736 }
737 }
738 }
739 }
740 }
741 }
742
743 return $tca;
744 }
745
746 /**
747 * Migrates selectTree fields deprecated options
748 *
749 * @param array $tca Incoming TCA
750 * @return array Migrated TCA
751 */
752 protected function migrateSelectTreeOptions(array $tca)
753 {
754 foreach ($tca as $table => &$tableDefinition) {
755 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
756 continue;
757 }
758 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
759 if (isset($fieldConfig['config']['renderType']) && $fieldConfig['config']['renderType'] === 'selectTree') {
760 if (isset($fieldConfig['config']['treeConfig']['appearance']['width'])) {
761 $this->messages[] = 'The selectTree field [\'treeConfig\'][\'appearance\'][\'width\'] setting is deprecated'
762 . ' and was removed in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
763 . '[\'treeConfig\'][\'appearance\'][\'width\'] ';
764 unset($fieldConfig['config']['treeConfig']['appearance']['width']);
765 }
766
767 if (isset($fieldConfig['config']['treeConfig']['appearance']['allowRecursiveMode'])) {
768 $this->messages[] = 'The selectTree field [\'treeConfig\'][\'appearance\'][\'allowRecursiveMode\'] setting is deprecated'
769 . ' and was removed in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
770 . '[\'treeConfig\'][\'appearance\'][\'allowRecursiveMode\'] ';
771 unset($fieldConfig['config']['treeConfig']['appearance']['allowRecursiveMode']);
772 }
773
774 if (isset($fieldConfig['config']['autoSizeMax'])) {
775 $this->messages[] = 'The selectTree field [\'autoSizeMax\'] setting is deprecated'
776 . ' and was removed in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'autoSizeMax\'].'
777 . ' The \'size\' value was adapted to the previous autoSizeMax value';
778 $fieldConfig['config']['size'] = $fieldConfig['config']['autoSizeMax'];
779 unset($fieldConfig['config']['autoSizeMax']);
780 }
781 }
782 }
783 }
784 return $tca;
785 }
786
787 /**
788 * Migrates selectTree fields deprecated options
789 *
790 * @param array $tca Incoming TCA
791 * @return array Migrated TCA
792 */
793 protected function migrateTSconfigSoftReferences(array $tca)
794 {
795 foreach ($tca as $table => &$tableDefinition) {
796 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
797 continue;
798 }
799 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
800 if (isset($fieldConfig['config'])) {
801 if (isset($fieldConfig['config']['softref'])) {
802 $softReferences = array_flip(GeneralUtility::trimExplode(',', $fieldConfig['config']['softref']));
803 $changed = false;
804 if (isset($softReferences['TSconfig'])) {
805 $changed = true;
806 unset($softReferences['TSconfig']);
807 }
808 if (isset($softReferences['TStemplate'])) {
809 $changed = true;
810 unset($softReferences['TStemplate']);
811 }
812 if ($changed) {
813 if (!empty($softReferences)) {
814 $softReferences = array_flip($softReferences);
815 $fieldConfig['config']['softref'] = implode(',', $softReferences);
816 } else {
817 unset($fieldConfig['config']['softref']);
818 }
819 $this->messages[] = 'The soft reference setting using \'TSconfig\' and '
820 . '\'TStemplate\' was removed in TCA ' . $table . '[\'columns\']'
821 . '[\'' . $fieldName . '\'][\'config\'][\'softref\']';
822 }
823 }
824 }
825 }
826 }
827 return $tca;
828 }
829
830 /**
831 * Removes the option "showIfRTE" for TCA type "check"
832 *
833 * @param array $tca Incoming TCA
834 * @return array Migrated TCA
835 */
836 protected function migrateShowIfRteOption(array $tca)
837 {
838 foreach ($tca as $table => &$tableDefinition) {
839 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
840 continue;
841 }
842 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
843 if (isset($fieldConfig['config']) && $fieldConfig['config']['type'] === 'check') {
844 if (isset($fieldConfig['config']['showIfRTE'])) {
845 unset($fieldConfig['config']['showIfRTE']);
846 $this->messages[] = 'The TCA setting \'showIfRTE\' was removed '
847 . 'in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
848 }
849 }
850 }
851 }
852 return $tca;
853 }
854
855 /**
856 * Casts "versioningWS" to bool, and removes "versioning_followPages"
857 *
858 * @param array $tca Incoming TCA
859 * @return array Migrated TCA
860 */
861 protected function migrateWorkspacesOptions(array $tca)
862 {
863 foreach ($tca as $table => &$tableDefinition) {
864 if (isset($tableDefinition['ctrl']['versioningWS']) && !is_bool($tableDefinition['ctrl']['versioningWS'])) {
865 $tableDefinition['ctrl']['versioningWS'] = (bool)$tableDefinition['ctrl']['versioningWS'];
866 $this->messages[] = 'The TCA setting \'versioningWS\' was set to a boolean value '
867 . 'in TCA ' . $table . '[\'ctrl\'][\'versioningWS\']';
868 }
869 if (isset($tableDefinition['ctrl']['versioning_followPages']) && !empty($tableDefinition['ctrl']['versioning_followPages'])) {
870 unset($tableDefinition['ctrl']['versioning_followPages']);
871 $this->messages[] = 'The TCA setting \'versioning_followPages\' was removed as it is unused '
872 . 'in TCA ' . $table . '[\'ctrl\'][\'versioning_followPages\']';
873 }
874 }
875 return $tca;
876 }
877
878 /**
879 * Removes "transForeignTable" and "transOrigPointerTable" which has been
880 * used for tables "pages" and "pages_languages_overlay" in the core only.
881 *
882 * @param array $tca Incoming TCA
883 * @return array Migrated TCA
884 */
885 protected function migrateTranslationTable(array $tca)
886 {
887 foreach ($tca as $table => &$tableDefinition) {
888 if (!empty($tableDefinition['ctrl']['transForeignTable'])) {
889 unset($tableDefinition['ctrl']['transForeignTable']);
890 $this->messages[] = 'The TCA setting \'transForeignTable\' was removed '
891 . 'in TCA ' . $table . '[\'ctrl\'][\'transForeignTable\']';
892 }
893 if (!empty($tableDefinition['ctrl']['transOrigPointerTable'])) {
894 unset($tableDefinition['ctrl']['transOrigPointerTable']);
895 $this->messages[] = 'The TCA setting \'transOrigPointerTable\' was removed '
896 . 'in TCA ' . $table . '[\'ctrl\'][\'transOrigPointerTable\']';
897 }
898 }
899 return $tca;
900 }
901
902 /**
903 * Move ['ctrl']['requestUpdate'] to 'onChange => "reload"' of single fields
904 *
905 * @param array $tca Incoming TCA
906 * @return array Migrated TCA
907 */
908 protected function migrateRequestUpdate(array $tca)
909 {
910 foreach ($tca as $table => &$tableDefinition) {
911 if (!empty($tableDefinition['ctrl']['requestUpdate'])) {
912 $fields = GeneralUtility::trimExplode(',', $tableDefinition['ctrl']['requestUpdate']);
913 $migratedFields = [];
914 foreach ($fields as $field) {
915 if (isset($tableDefinition['columns'][$field])) {
916 $tableDefinition['columns'][$field]['onChange'] = 'reload';
917 $migratedFields[] = $field;
918 }
919 }
920 $this->messages[] = 'The TCA setting [\'ctrl\'][\'requestUpdate\'] was removed from '
921 . ' table ' . $table . '. The column field(s) "' . implode('" and "', $fields) . '" were updated'
922 . ' and contain option "\'onChange\' => \'reload\'" parallel to \'config\' and \'label\' section.';
923 unset($tableDefinition['ctrl']['requestUpdate']);
924 }
925 }
926 return $tca;
927 }
928 }