[TASK] Use null coalescing operator where possible
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Migrations / TcaMigration.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Core\Migrations;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Migrate TCA from old to new syntax. Used in bootstrap and Flex Form Data Structures.
22 *
23 * @internal Class and API may change any time.
24 */
25 class TcaMigration
26 {
27 /**
28 * Accumulate migration messages
29 *
30 * @var array
31 */
32 protected $messages = [];
33
34 /**
35 * Run some general TCA validations, then migrate old TCA to new TCA.
36 *
37 * This class is typically called within bootstrap with empty caches after all TCA
38 * files from extensions have been loaded. The migration is then applied and
39 * the migrated result is cached.
40 * For flex form TCA, this class is called dynamically if opening a record in the backend.
41 *
42 * See unit tests for details.
43 *
44 * @param array $tca
45 * @return array
46 */
47 public function migrate(array $tca): array
48 {
49 $this->validateTcaType($tca);
50
51 $tca = $this->migrateColumnsConfig($tca);
52 $tca = $this->migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig($tca);
53 $tca = $this->migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig($tca);
54 $tca = $this->migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides($tca);
55 $tca = $this->migrateShowItemAdditionalPaletteToOwnPalette($tca);
56 $tca = $this->migrateIconsForFormFieldWizardToNewLocation($tca);
57 $tca = $this->migrateExtAndSysextPathToEXTPath($tca);
58 $tca = $this->migrateIconsInOptionTags($tca);
59 $tca = $this->migrateIconfileRelativePathOrFilenameOnlyToExtReference($tca);
60 $tca = $this->migrateSelectFieldRenderType($tca);
61 $tca = $this->migrateSelectFieldIconTable($tca);
62 $tca = $this->migrateElementBrowserWizardToLinkHandler($tca);
63 $tca = $this->migrateDefaultExtrasRteTransFormOptions($tca);
64 $tca = $this->migrateSelectTreeOptions($tca);
65 $tca = $this->migrateTSconfigSoftReferences($tca);
66 $tca = $this->migrateShowIfRteOption($tca);
67 $tca = $this->migrateWorkspacesOptions($tca);
68 $tca = $this->migrateTranslationTable($tca);
69 $tca = $this->migrateL10nModeDefinitions($tca);
70 $tca = $this->migratePageLocalizationDefinitions($tca);
71 $tca = $this->migrateInlineLocalizationMode($tca);
72 $tca = $this->migrateRequestUpdate($tca);
73 $tca = $this->migrateInputDateTimeToRenderType($tca);
74 $tca = $this->migrateWizardEnableByTypeConfigToColumnsOverrides($tca);
75 $tca = $this->migrateColorPickerWizardToRenderType($tca);
76 $tca = $this->migrateSelectWizardToValuePicker($tca);
77 $tca = $this->migrateSliderWizardToSliderConfiguration($tca);
78 $tca = $this->migrateLinkWizardToRenderTypeAndFieldControl($tca);
79 $tca = $this->migrateEditWizardToFieldControl($tca);
80 $tca = $this->migrateAddWizardToFieldControl($tca);
81 $tca = $this->migrateListWizardToFieldControl($tca);
82 $tca = $this->migrateLastPiecesOfDefaultExtras($tca);
83 $tca = $this->migrateTableWizardToRenderType($tca);
84 $tca = $this->migrateFullScreenRichtextToFieldControl($tca);
85 $tca = $this->migrateSuggestWizardTypeGroup($tca);
86 $tca = $this->migrateOptionsOfTypeGroup($tca);
87 $tca = $this->migrateSelectShowIconTable($tca);
88 $tca = $this->migrateImageManipulationConfig($tca);
89 $tca = $this->migrateinputDateTimeMax($tca);
90 $tca = $this->migrateInlineOverrideChildTca($tca);
91 $tca = $this->migrateLocalizeChildrenAtParentLocalization($tca);
92 $tca = $this->migratePagesLanguageOverlayRemoval($tca);
93 return $tca;
94 }
95
96 /**
97 * Get messages of migrated fields. Can be used for deprecation messages after migrate() was called.
98 *
99 * @return array Migration messages
100 */
101 public function getMessages(): array
102 {
103 return $this->messages;
104 }
105
106 /**
107 * Check for required TCA configuration
108 *
109 * @param array $tca Incoming TCA
110 */
111 protected function validateTcaType(array $tca)
112 {
113 foreach ($tca as $table => $tableDefinition) {
114 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
115 continue;
116 }
117 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
118 if (isset($fieldConfig['config']) && is_array($fieldConfig['config']) && empty($fieldConfig['config']['type'])) {
119 throw new \UnexpectedValueException(
120 'Missing "type" in TCA of field "[\'' . $table . '\'][\'' . $fieldName . '\'][\'config\']".',
121 1482394401
122 );
123 }
124 }
125 }
126 }
127
128 /**
129 * Find columns fields that don't have a 'config' section at all, add
130 * ['config']['type'] = 'none'; for those to enforce config
131 *
132 * @param array $tca Incoming TCA
133 * @return array
134 */
135 protected function migrateColumnsConfig(array $tca): array
136 {
137 foreach ($tca as $table => &$tableDefinition) {
138 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
139 continue;
140 }
141 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
142 if ((!isset($fieldConfig['config']) || !is_array($fieldConfig['config'])) && !isset($fieldConfig['type'])) {
143 $fieldConfig['config'] = [
144 'type' => 'none',
145 ];
146 $this->messages[] = 'TCA table "' . $table . '" columns field "' . $fieldName . '"'
147 . ' had no mandatory "config" section. This has been added with default type "none":'
148 . ' TCA "' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'type\'] = \'none\'"';
149 }
150 }
151 }
152 return $tca;
153 }
154
155 /**
156 * Migrate type=text field with t3editor wizard to renderType=t3editor without this wizard
157 *
158 * @param array $tca Incoming TCA
159 * @return array Migrated TCA
160 */
161 protected function migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig(array $tca): array
162 {
163 $newTca = $tca;
164 foreach ($tca as $table => $tableDefinition) {
165 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
166 continue;
167 }
168 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
169 if (
170 !empty($fieldConfig['config']['type']) // type is set
171 && trim($fieldConfig['config']['type']) === 'text' // to "text"
172 && isset($fieldConfig['config']['wizards'])
173 && is_array($fieldConfig['config']['wizards']) // and there are wizards
174 ) {
175 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
176 if (
177 !empty($wizardConfig['userFunc']) // a userFunc is defined
178 && trim($wizardConfig['userFunc']) === 'TYPO3\\CMS\\T3editor\\FormWizard->main' // and set to FormWizard
179 && (
180 !isset($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is not set
181 || (isset($wizardConfig['enableByTypeConfig']) && !$wizardConfig['enableByTypeConfig']) // or set, but not enabled
182 )
183 ) {
184 // Set renderType from text to t3editor
185 $newTca[$table]['columns'][$fieldName]['config']['renderType'] = 't3editor';
186 // Unset this wizard definition
187 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
188 // Move format parameter
189 if (!empty($wizardConfig['params']['format'])) {
190 $newTca[$table]['columns'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
191 }
192 $this->messages[] = 'The t3editor wizard using \'type\' = \'text\' has been migrated to a \'renderType\' = \'t3editor\' definition.'
193 . 'It has been migrated from TCA "' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'t3editor\']"'
194 . 'to "' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'renderType\'] = \'t3editor\'"';
195 }
196 }
197 // If no wizard is left after migration, unset the whole sub array
198 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
199 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
200 }
201 }
202 }
203 }
204 return $newTca;
205 }
206
207 /**
208 * Remove "style pointer", the 5th parameter from "types" "showitem" configuration.
209 * Move "specConf", 4th parameter from "types" "showitem" to "types" "columnsOverrides".
210 *
211 * @param array $tca Incoming TCA
212 * @return array Modified TCA
213 */
214 protected function migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig(array $tca): array
215 {
216 $newTca = $tca;
217 foreach ($tca as $table => $tableDefinition) {
218 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
219 continue;
220 }
221 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
222 if (!isset($typeArray['showitem']) || !is_string($typeArray['showitem']) || strpos($typeArray['showitem'], ';') === false) {
223 // Continue directly if no semicolon is found
224 continue;
225 }
226 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], true);
227 $newFieldStrings = [];
228 foreach ($itemList as $fieldString) {
229 $fieldString = rtrim($fieldString, ';');
230 // Unpack the field definition, migrate and remove as much as possible
231 // Keep empty parameters in trimExplode here (third parameter FALSE), so position is not changed
232 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
233 $fieldArray = [
234 'fieldName' => $fieldArray[0] ?? '',
235 'fieldLabel' => $fieldArray[1] ?? null,
236 'paletteName' => $fieldArray[2] ?? null,
237 'fieldExtra' => $fieldArray[3] ?? null,
238 ];
239 if (!empty($fieldArray['fieldExtra'])) {
240 // Move fieldExtra "specConf" to columnsOverrides "defaultExtras"
241 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'])) {
242 $newTca[$table]['types'][$typeName]['columnsOverrides'] = [];
243 }
244 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']])) {
245 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']] = [];
246 }
247 // Merge with given defaultExtras from columns.
248 // They will be the first part of the string, so if "specConf" from types changes the same settings,
249 // those will override settings from defaultExtras of columns
250 $newDefaultExtras = [];
251 if (!empty($tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'])) {
252 $newDefaultExtras[] = $tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'];
253 }
254 $newDefaultExtras[] = $fieldArray['fieldExtra'];
255 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']]['defaultExtras'] = implode(':', $newDefaultExtras);
256 }
257 unset($fieldArray['fieldExtra']);
258 if (count($fieldArray) === 3 && empty($fieldArray['paletteName'])) {
259 unset($fieldArray['paletteName']);
260 }
261 if (count($fieldArray) === 2 && empty($fieldArray['fieldLabel'])) {
262 unset($fieldArray['fieldLabel']);
263 }
264 if (count($fieldArray) === 1 && empty($fieldArray['fieldName'])) {
265 // The field may vanish if nothing is left
266 unset($fieldArray['fieldName']);
267 }
268 $newFieldString = implode(';', $fieldArray);
269 if ($newFieldString !== $fieldString) {
270 $this->messages[] = 'The 4th parameter \'specConf\' of the field \'showitem\' with fieldName = \'' . $fieldArray['fieldName'] . '\' has been migrated, from TCA table "'
271 . $table . '[\'types\'][\'' . $typeName . '\'][\'showitem\']"' . 'to "'
272 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldArray['fieldName'] . '\'][\'defaultExtras\']".';
273 }
274 if (!empty($newFieldString)) {
275 $newFieldStrings[] = $newFieldString;
276 }
277 }
278 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
279 }
280 }
281 return $newTca;
282 }
283
284 /**
285 * Migrate type=text field with t3editor wizard that is "enableByTypeConfig" to columnsOverrides
286 * with renderType=t3editor
287 *
288 * @param array $tca Incoming TCA
289 * @return array Migrated TCA
290 */
291 protected function migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides(array $tca): array
292 {
293 $newTca = $tca;
294 foreach ($tca as $table => $tableDefinition) {
295 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
296 continue;
297 }
298 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
299 if (
300 !empty($fieldConfig['config']['type']) // type is set
301 && trim($fieldConfig['config']['type']) === 'text' // to "text"
302 && isset($fieldConfig['config']['wizards'])
303 && is_array($fieldConfig['config']['wizards']) // and there are wizards
304 ) {
305 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
306 if (
307 !empty($wizardConfig['userFunc']) // a userFunc is defined
308 && trim($wizardConfig['userFunc']) === 'TYPO3\CMS\T3editor\FormWizard->main' // and set to FormWizard
309 && !empty($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is enabled
310 ) {
311 // Remove this wizard
312 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
313 // Find configured types that use this wizard
314 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
315 // No type definition at all ... continue directly
316 continue;
317 }
318 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
319 if (
320 empty($typeArray['columnsOverrides'][$fieldName]['defaultExtras'])
321 || strpos($typeArray['columnsOverrides'][$fieldName]['defaultExtras'], $wizardName) === false
322 ) {
323 // Continue directly if this wizard is not enabled for given type
324 continue;
325 }
326 $defaultExtras = $typeArray['columnsOverrides'][$fieldName]['defaultExtras'];
327 $defaultExtrasArray = GeneralUtility::trimExplode(':', $defaultExtras, true);
328 $newDefaultExtrasArray = [];
329 foreach ($defaultExtrasArray as $fieldExtraField) {
330 // There might be multiple enabled wizards separated by | ... split them
331 if (substr($fieldExtraField, 0, 8) === 'wizards[') {
332 $enabledWizards = substr($fieldExtraField, 8, strlen($fieldExtraField) - 8); // Cut off "wizards[
333 $enabledWizards = substr($enabledWizards, 0, strlen($enabledWizards) - 1);
334 $enabledWizardsArray = GeneralUtility::trimExplode('|', $enabledWizards, true);
335 $newEnabledWizardsArray = [];
336 foreach ($enabledWizardsArray as $enabledWizardName) {
337 if ($enabledWizardName === $wizardName) {
338 // Found a columnsOverrides configuration that has this wizard enabled
339 // Force renderType = t3editor
340 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['renderType'] = 't3editor';
341 // Transfer format option if given
342 if (!empty($wizardConfig['params']['format'])) {
343 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
344 }
345 $this->messages[] = 'The t3editor wizard using \'type\' = \'text\', with the "enableByTypeConfig" wizard set to 1,'
346 . 'has been migrated to the \'renderType\' = \'t3editor\' definition.'
347 . 'It has been migrated from TCA "' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'t3editor\']"'
348 . 'to "' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'renderType\'] = \'t3editor\'"';
349 } else {
350 // Some other enabled wizard
351 $newEnabledWizardsArray[] = $enabledWizardName;
352 }
353 }
354 if (!empty($newEnabledWizardsArray)) {
355 $newDefaultExtrasArray[] = 'wizards[' . implode('|', $newEnabledWizardsArray) . ']';
356 }
357 } else {
358 $newDefaultExtrasArray[] = $fieldExtraField;
359 }
360 }
361 if (!empty($newDefaultExtrasArray)) {
362 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras'] = implode(':', $newDefaultExtrasArray);
363 } else {
364 unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras']);
365 }
366 }
367 }
368 }
369 // If no wizard is left after migration, unset the whole sub array
370 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
371 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
372 }
373 }
374 }
375 }
376 return $newTca;
377 }
378
379 /**
380 * Migrate types showitem 'aField;aLabel;aPalette' to 'afield;aLabel, --palette--;;aPalette'
381 *
382 * Old showitem can have a syntax like:
383 * fieldName;aLabel;aPalette
384 * This way, the palette with name "aPalette" is rendered after fieldName.
385 * The migration parses this to a syntax like:
386 * fieldName;aLabel, --palette--;;paletteName
387 *
388 * @param array $tca Incoming TCA
389 * @return array Migrated TCA
390 */
391 protected function migrateShowItemAdditionalPaletteToOwnPalette(array $tca): array
392 {
393 $newTca = $tca;
394 foreach ($tca as $table => $tableDefinition) {
395 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
396 continue;
397 }
398 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
399 if (
400 !isset($typeArray['showitem'])
401 || !is_string($typeArray['showitem'])
402 || strpos($typeArray['showitem'], ';') === false // no field parameters
403 ) {
404 continue;
405 }
406 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], true);
407 $newFieldStrings = [];
408 foreach ($itemList as $fieldString) {
409 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
410 $fieldArray = [
411 'fieldName' => $fieldArray[0] ?? '',
412 'fieldLabel' => $fieldArray[1] ?? null,
413 'paletteName' => $fieldArray[2] ?? null,
414 ];
415 if ($fieldArray['fieldName'] !== '--palette--' && $fieldArray['paletteName'] !== null) {
416 if ($fieldArray['fieldLabel']) {
417 $fieldString = $fieldArray['fieldName'] . ';' . $fieldArray['fieldLabel'];
418 } else {
419 $fieldString = $fieldArray['fieldName'];
420 }
421 $paletteString = '--palette--;;' . $fieldArray['paletteName'];
422 $this->messages[] = 'Migrated \'showitem\' field from TCA table '
423 . $table . '[\'types\'][\'' . $typeName . '\']" : Moved additional palette'
424 . ' with name "' . $table . '[\'types\'][\'' . $typeName . '\'][\'' . $fieldArray['paletteName'] . '\']" as 3rd argument of field "'
425 . $table . '[\'types\'][\'' . $typeName . '\'][\'' . $fieldArray['fieldName'] . '\']"'
426 . 'to an own palette. The result of this part is: "' . $fieldString . ', ' . $paletteString . '"';
427 $newFieldStrings[] = $fieldString;
428 $newFieldStrings[] = $paletteString;
429 } else {
430 $newFieldStrings[] = $fieldString;
431 }
432 }
433 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
434 }
435 }
436 return $newTca;
437 }
438
439 /**
440 * Migrate core icons for form field wizard to new location
441 *
442 * @param array $tca Incoming TCA
443 * @return array Migrated TCA
444 */
445 protected function migrateIconsForFormFieldWizardToNewLocation(array $tca): array
446 {
447 $newTca = $tca;
448
449 $newFileLocations = [
450 'add.gif' => 'actions-add',
451 'link_popup.gif' => 'actions-wizard-link',
452 'wizard_rte2.gif' => 'actions-wizard-rte',
453 'wizard_table.gif' => 'content-table',
454 'edit2.gif' => 'actions-open',
455 'list.gif' => 'actions-system-list-open',
456 'wizard_forms.gif' => 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_forms.gif',
457 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_add.gif' => 'actions-add',
458 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_table.gif' => 'content-table',
459 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_edit.gif' => 'actions-open',
460 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_list.gif' => 'actions-system-list-open',
461 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_link.gif' => 'actions-wizard-link',
462 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_rte.gif' => 'actions-wizard-rte'
463 ];
464 $oldFileNames = array_keys($newFileLocations);
465
466 foreach ($tca as $table => $tableDefinition) {
467 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
468 continue;
469 }
470 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
471 if (
472 isset($fieldConfig['config']['wizards'])
473 && is_array($fieldConfig['config']['wizards']) // and there are wizards
474 ) {
475 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
476 if (!is_array($wizardConfig)) {
477 continue;
478 }
479
480 foreach ($wizardConfig as $option => $value) {
481 if ($option === 'icon' && in_array($value, $oldFileNames, true)) {
482 $newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]['icon'] = $newFileLocations[$value];
483 $this->messages[] = 'The icon path of wizard "' . $wizardName
484 . '" from TCA table "'
485 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\'][\'icon\']"'
486 . 'has been migrated to '
487 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\'][\'icon\']" = \'' . $newFileLocations[$value] . '\'.';
488 }
489 }
490 }
491 }
492 }
493 }
494
495 return $newTca;
496 }
497
498 /**
499 * Migrate file reference which starts with ext/ or sysext/ to EXT:
500 *
501 * @param array $tca Incoming TCA
502 * @return array Migrated TCA
503 */
504 protected function migrateExtAndSysextPathToEXTPath(array $tca): array
505 {
506 foreach ($tca as $table => &$tableDefinition) {
507 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
508 continue;
509 }
510 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
511 if (
512 !empty($fieldConfig['config']['type']) // type is set
513 && trim($fieldConfig['config']['type']) === 'select' // to "select"
514 && isset($fieldConfig['config']['items'])
515 && is_array($fieldConfig['config']['items']) // and there are items
516 ) {
517 foreach ($fieldConfig['config']['items'] as &$itemConfig) {
518 // more then two values? then the third entry is the image path
519 if (!empty($itemConfig[2])) {
520 $tcaPath = implode('.', [$table, 'columns', $fieldName, 'config', 'items']);
521 $pathParts = GeneralUtility::trimExplode('/', $itemConfig[2]);
522 // remove first element (ext or sysext)
523 array_shift($pathParts);
524 $path = implode('/', $pathParts);
525 // If the path starts with ext/ or sysext/ migrate it
526 if (
527 strpos($itemConfig[2], 'ext/') === 0
528 || strpos($itemConfig[2], 'sysext/') === 0
529 ) {
530 $this->messages[] = '[' . $tcaPath . '] ext/ or sysext/ within the path (' . $path . ') in items array is deprecated, use EXT: reference';
531 $itemConfig[2] = 'EXT:' . $path;
532 } elseif (strpos($itemConfig[2], 'i/') === 0) {
533 $this->messages[] = '[' . $tcaPath . '] i/ within the path (' . $path . ') in items array is deprecated, use EXT: reference';
534 $itemConfig[2] = 'EXT:backend/Resources/Public/Images/' . substr($itemConfig[2], 2);
535 }
536 }
537 }
538 }
539 }
540 }
541 return $tca;
542 }
543
544 /**
545 * Migrate "iconsInOptionTags" for "select" TCA fields
546 *
547 * @param array $tca Incoming TCA
548 * @return array Migrated TCA
549 */
550 protected function migrateIconsInOptionTags(array $tca): array
551 {
552 $newTca = $tca;
553
554 foreach ($newTca as $table => &$tableDefinition) {
555 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
556 continue;
557 }
558 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
559 if (isset($fieldConfig['config']['iconsInOptionTags'])) {
560 unset($fieldConfig['config']['iconsInOptionTags']);
561 $this->messages[] = 'Configuration option \'iconsInOptionTags\' was removed from field "' . $fieldName . '" in TCA table "' . $table . '[\'config\']"';
562 }
563 }
564 }
565
566 return $newTca;
567 }
568
569 /**
570 * Migrate "iconfile" references which starts with ../ to EXT: and consisting of filename only to absolute paths in EXT:t3skin
571 *
572 * @param array $tca Incoming TCA
573 * @return array Migrated TCA
574 */
575 protected function migrateIconfileRelativePathOrFilenameOnlyToExtReference(array $tca): array
576 {
577 foreach ($tca as $table => &$tableDefinition) {
578 if (!isset($tableDefinition['ctrl']) || !is_array($tableDefinition['ctrl'])) {
579 continue;
580 }
581 if (!isset($tableDefinition['ctrl']['iconfile'])) {
582 continue;
583 }
584 if (strpos($tableDefinition['ctrl']['iconfile'], '../typo3conf/ext/') === 0) {
585 $tableDefinition['ctrl']['iconfile'] = str_replace('../typo3conf/ext/', 'EXT:', $tableDefinition['ctrl']['iconfile']);
586 $tcaPath = implode('.', [$table, 'ctrl', 'iconfile']);
587 $this->messages[] = '[' . $tcaPath . '] relative path to ../typo3conf/ext/ is deprecated, use EXT: instead';
588 } elseif (strpos($tableDefinition['ctrl']['iconfile'], '/') === false) {
589 $tableDefinition['ctrl']['iconfile'] = 'EXT:backend/Resources/Public/Images/' . $tableDefinition['ctrl']['iconfile'];
590 $tcaPath = implode('.', [$table, 'ctrl', 'iconfile']);
591 $this->messages[] = '[' . $tcaPath . '] filename only is deprecated, use EXT: or absolute reference instead';
592 }
593 }
594 return $tca;
595 }
596
597 /**
598 * Migrate "type=select" with "renderMode=[tree|singlebox|checkbox]" to "renderType=[selectTree|selectSingleBox|selectCheckBox]".
599 * This migration also take care of "maxitems" settings and set "renderType=[selectSingle|selectMultipleSideBySide]" if no other
600 * renderType is already set.
601 *
602 * @param array $tca
603 * @return array
604 */
605 public function migrateSelectFieldRenderType(array $tca): array
606 {
607 $newTca = $tca;
608
609 foreach ($newTca as $table => &$tableDefinition) {
610 if (empty($tableDefinition['columns'])) {
611 continue;
612 }
613
614 foreach ($tableDefinition['columns'] as $columnName => &$columnDefinition) {
615 // Only handle select fields.
616 if (empty($columnDefinition['config']['type']) || $columnDefinition['config']['type'] !== 'select') {
617 continue;
618 }
619 // Do not handle field where the render type is set.
620 if (!empty($columnDefinition['config']['renderType'])) {
621 continue;
622 }
623
624 $tableColumnInfo = 'table "' . $table . '[\'columns\'][\'' . $columnName . '\']"';
625 $this->messages[] = 'Using the \'type\' = \'select\' field in "' . $table . '[\'columns\'][\'' . $columnName . '\'][\'config\'][\'type\'] = \'select\'" without the "renderType" setting in "'
626 . $table . '[\'columns\'][\'' . $columnName . '\'][\'config\'][\'renderType\']" is deprecated.';
627
628 $columnConfig = &$columnDefinition['config'];
629 if (!empty($columnConfig['renderMode'])) {
630 $this->messages[] = 'The "renderMode" setting for select fields is deprecated. Please use "renderType" instead in ' . $tableColumnInfo;
631 switch ($columnConfig['renderMode']) {
632 case 'tree':
633 $columnConfig['renderType'] = 'selectTree';
634 break;
635 case 'singlebox':
636 $columnConfig['renderType'] = 'selectSingleBox';
637 break;
638 case 'checkbox':
639 $columnConfig['renderType'] = 'selectCheckBox';
640 break;
641 default:
642 $this->messages[] = 'The render mode ' . $columnConfig['renderMode'] . ' is invalid for the select field in ' . $tableColumnInfo;
643 }
644 continue;
645 }
646
647 $maxItems = !empty($columnConfig['maxitems']) ? (int)$columnConfig['maxitems'] : 1;
648 if ($maxItems <= 1) {
649 $columnConfig['renderType'] = 'selectSingle';
650 } else {
651 $columnConfig['renderType'] = 'selectMultipleSideBySide';
652 }
653 }
654 }
655
656 return $newTca;
657 }
658
659 /**
660 * Migrate the visibility of the icon table for fields with "renderType=selectSingle"
661 *
662 * @param array $tca
663 * @return array Migrated TCA
664 */
665 public function migrateSelectFieldIconTable(array $tca): array
666 {
667 foreach ($tca as $table => &$tableDefinition) {
668 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
669 continue;
670 }
671 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
672 if (empty($fieldConfig['config']['renderType']) || $fieldConfig['config']['renderType'] !== 'selectSingle') {
673 continue;
674 }
675 if (array_key_exists('noIconsBelowSelect', $fieldConfig['config'])) {
676 $this->messages[] = 'The "noIconsBelowSelect" setting for select fields in table "'
677 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']" was removed. Please define the setting "showIconTable" in table "'
678 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'showIconTable\']"';
679 if (!$fieldConfig['config']['noIconsBelowSelect']) {
680 // If old setting was explicitly false, enable icon table if not defined yet
681 if (!array_key_exists('showIconTable', $fieldConfig['config'])) {
682 $fieldConfig['config']['showIconTable'] = true;
683 }
684 }
685 unset($fieldConfig['config']['noIconsBelowSelect']);
686 }
687 if (array_key_exists('suppress_icons', $fieldConfig['config'])) {
688 $this->messages[] = 'The "suppress_icons" setting for select fields in table "'
689 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']" was removed. Please define the setting "showIconTable" for table "'
690 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'showIconTable\']"';
691 unset($fieldConfig['config']['suppress_icons']);
692 }
693 if (array_key_exists('foreign_table_loadIcons', $fieldConfig['config'])) {
694 $this->messages[] = 'The "foreign_table_loadIcons" setting for select fields in table "'
695 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']" was removed. Please define the setting "showIconTable" for table "'
696 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'showIconTable\']"';
697 unset($fieldConfig['config']['foreign_table_loadIcons']);
698 }
699 }
700 }
701 return $tca;
702 }
703
704 /**
705 * Migrate wizard "wizard_element_browser" used in mode "wizard" to use the "wizard_link" instead
706 *
707 * @param array $tca
708 * @return array Migrated TCA
709 */
710 protected function migrateElementBrowserWizardToLinkHandler(array $tca): array
711 {
712 foreach ($tca as $table => &$tableDefinition) {
713 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
714 continue;
715 }
716 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
717 if (
718 isset($fieldConfig['config']['wizards']['link']['module']['name']) && $fieldConfig['config']['wizards']['link']['module']['name'] === 'wizard_element_browser'
719 && isset($fieldConfig['config']['wizards']['link']['module']['urlParameters']['mode']) && $fieldConfig['config']['wizards']['link']['module']['urlParameters']['mode'] === 'wizard'
720 ) {
721 $fieldConfig['config']['wizards']['link']['module']['name'] = 'wizard_link';
722 unset($fieldConfig['config']['wizards']['link']['module']['urlParameters']['mode']);
723 if (empty($fieldConfig['config']['wizards']['link']['module']['urlParameters'])) {
724 unset($fieldConfig['config']['wizards']['link']['module']['urlParameters']);
725 }
726 $this->messages[] = 'Reference to "wizard_element_browser" was migrated from"'
727 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'link\'][\'module\'][\'name\'] === \'wizard_element_browser\'"'
728 . 'to new "wizard_link", "'
729 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'link\'][\'module\'][\'name\'] = \'wizard_link\' "';
730 }
731 }
732 }
733 return $tca;
734 }
735
736 /**
737 * Migrate defaultExtras "richtext:rte_transform[mode=ts_css]" and similar stuff like
738 * "richtext:rte_transform[mode=ts_css]" to "richtext:rte_transform"
739 *
740 * @param array $tca
741 * @return array Migrated TCA
742 */
743 protected function migrateDefaultExtrasRteTransFormOptions(array $tca): array
744 {
745 foreach ($tca as $table => &$tableDefinition) {
746 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
747 continue;
748 }
749 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
750 if (isset($fieldConfig['defaultExtras'])) {
751 $originalValue = $fieldConfig['defaultExtras'];
752 $defaultExtrasArray = GeneralUtility::trimExplode(':', $originalValue, true);
753 $isRichtextField = false;
754 foreach ($defaultExtrasArray as $defaultExtrasField) {
755 if (substr($defaultExtrasField, 0, 8) === 'richtext') {
756 $isRichtextField = true;
757 $fieldConfig['config']['enableRichtext'] = true;
758 $fieldConfig['config']['richtextConfiguration'] = 'default';
759 }
760 }
761 if ($isRichtextField) {
762 unset($fieldConfig['defaultExtras']);
763 $this->messages[] = 'RTE configuration via \'defaultExtras\' options are deprecated. String "' . $originalValue . '" in TCA'
764 . ' ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'defaultExtras\'] was changed to'
765 . ' options in ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
766 }
767 }
768 }
769 }
770
771 foreach ($tca as $table => &$tableDefinition) {
772 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
773 continue;
774 }
775 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
776 if (!isset($typeArray['columnsOverrides']) || !is_array($typeArray['columnsOverrides'])) {
777 continue;
778 }
779 foreach ($typeArray['columnsOverrides'] as $fieldName => &$fieldConfig) {
780 if (isset($fieldConfig['defaultExtras'])) {
781 $originalValue = $fieldConfig['defaultExtras'];
782 $defaultExtrasArray = GeneralUtility::trimExplode(':', $originalValue, true);
783 $isRichtextField = false;
784 foreach ($defaultExtrasArray as $defaultExtrasField) {
785 if (substr($defaultExtrasField, 0, 8) === 'richtext') {
786 $isRichtextField = true;
787 $fieldConfig['config']['enableRichtext'] = true;
788 $fieldConfig['config']['richtextConfiguration'] = 'default';
789 }
790 }
791 if ($isRichtextField) {
792 unset($fieldConfig['defaultExtras']);
793 $this->messages[] = 'RTE configuration via \'defaultExtras\' options are deprecated. String "' . $originalValue . '" in TCA'
794 . ' ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\'][\'defaultExtras\']' .
795 ' was changed to options in ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
796 }
797 }
798 }
799 }
800 }
801
802 return $tca;
803 }
804
805 /**
806 * Migrates selectTree fields deprecated options
807 *
808 * @param array $tca Incoming TCA
809 * @return array Migrated TCA
810 */
811 protected function migrateSelectTreeOptions(array $tca): array
812 {
813 foreach ($tca as $table => &$tableDefinition) {
814 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
815 continue;
816 }
817 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
818 if (isset($fieldConfig['config']['renderType']) && $fieldConfig['config']['renderType'] === 'selectTree') {
819 if (isset($fieldConfig['config']['treeConfig']['appearance']['width'])) {
820 $this->messages[] = 'The selectTree field [\'treeConfig\'][\'appearance\'][\'width\'] setting is deprecated'
821 . ' and was removed in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
822 . '[\'treeConfig\'][\'appearance\'][\'width\'] ';
823 unset($fieldConfig['config']['treeConfig']['appearance']['width']);
824 }
825
826 if (isset($fieldConfig['config']['treeConfig']['appearance']['allowRecursiveMode'])) {
827 $this->messages[] = 'The selectTree field [\'treeConfig\'][\'appearance\'][\'allowRecursiveMode\'] setting is deprecated'
828 . ' and was removed in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
829 . '[\'treeConfig\'][\'appearance\'][\'allowRecursiveMode\'] ';
830 unset($fieldConfig['config']['treeConfig']['appearance']['allowRecursiveMode']);
831 }
832
833 if (isset($fieldConfig['config']['autoSizeMax'])) {
834 $this->messages[] = 'The selectTree field [\'autoSizeMax\'] setting is deprecated'
835 . ' and was removed in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'autoSizeMax\'].'
836 . ' The \'size\' value was adapted to the previous autoSizeMax value';
837 $fieldConfig['config']['size'] = $fieldConfig['config']['autoSizeMax'];
838 unset($fieldConfig['config']['autoSizeMax']);
839 }
840 }
841 }
842 }
843 return $tca;
844 }
845
846 /**
847 * Migrates selectTree fields deprecated options
848 *
849 * @param array $tca Incoming TCA
850 * @return array Migrated TCA
851 */
852 protected function migrateTSconfigSoftReferences(array $tca): array
853 {
854 foreach ($tca as $table => &$tableDefinition) {
855 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
856 continue;
857 }
858 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
859 if (isset($fieldConfig['config'])) {
860 if (isset($fieldConfig['config']['softref'])) {
861 $softReferences = array_flip(GeneralUtility::trimExplode(',', $fieldConfig['config']['softref']));
862 $changed = false;
863 if (isset($softReferences['TSconfig'])) {
864 $changed = true;
865 unset($softReferences['TSconfig']);
866 }
867 if (isset($softReferences['TStemplate'])) {
868 $changed = true;
869 unset($softReferences['TStemplate']);
870 }
871 if ($changed) {
872 if (!empty($softReferences)) {
873 $softReferences = array_flip($softReferences);
874 $fieldConfig['config']['softref'] = implode(',', $softReferences);
875 } else {
876 unset($fieldConfig['config']['softref']);
877 }
878 $this->messages[] = 'The soft reference setting using \'TSconfig\' and '
879 . '\'TStemplate\' was removed in TCA ' . $table . '[\'columns\']'
880 . '[\'' . $fieldName . '\'][\'config\'][\'softref\']';
881 }
882 }
883 }
884 }
885 }
886 return $tca;
887 }
888
889 /**
890 * Removes the option "showIfRTE" for TCA type "check"
891 *
892 * @param array $tca Incoming TCA
893 * @return array Migrated TCA
894 */
895 protected function migrateShowIfRteOption(array $tca): array
896 {
897 foreach ($tca as $table => &$tableDefinition) {
898 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
899 continue;
900 }
901 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
902 if (isset($fieldConfig['config']) && $fieldConfig['config']['type'] === 'check') {
903 if (isset($fieldConfig['config']['showIfRTE'])) {
904 unset($fieldConfig['config']['showIfRTE']);
905 $this->messages[] = 'The TCA setting \'showIfRTE\' was removed '
906 . 'in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
907 }
908 }
909 }
910 }
911 return $tca;
912 }
913
914 /**
915 * Casts "versioningWS" to bool, and removes "versioning_followPages"
916 *
917 * @param array $tca Incoming TCA
918 * @return array Migrated TCA
919 */
920 protected function migrateWorkspacesOptions(array $tca): array
921 {
922 foreach ($tca as $table => &$tableDefinition) {
923 if (isset($tableDefinition['ctrl']['versioningWS']) && !is_bool($tableDefinition['ctrl']['versioningWS'])) {
924 $tableDefinition['ctrl']['versioningWS'] = (bool)$tableDefinition['ctrl']['versioningWS'];
925 $this->messages[] = 'The TCA setting \'versioningWS\' was set to a boolean value '
926 . 'in TCA ' . $table . '[\'ctrl\'][\'versioningWS\']';
927 }
928 if (isset($tableDefinition['ctrl']['versioning_followPages']) && !empty($tableDefinition['ctrl']['versioning_followPages'])) {
929 unset($tableDefinition['ctrl']['versioning_followPages']);
930 $this->messages[] = 'The TCA setting \'versioning_followPages\' was removed as it is unused '
931 . 'in TCA ' . $table . '[\'ctrl\'][\'versioning_followPages\']';
932 }
933 }
934 return $tca;
935 }
936
937 /**
938 * Removes "transForeignTable" and "transOrigPointerTable" which has been
939 * used for tables "pages" and "pages_languages_overlay" in the core only.
940 *
941 * @param array $tca Incoming TCA
942 * @return array Migrated TCA
943 */
944 protected function migrateTranslationTable(array $tca): array
945 {
946 foreach ($tca as $table => &$tableDefinition) {
947 if (!empty($tableDefinition['ctrl']['transForeignTable'])) {
948 unset($tableDefinition['ctrl']['transForeignTable']);
949 $this->messages[] = 'The TCA setting \'transForeignTable\' was removed '
950 . 'in TCA ' . $table . '[\'ctrl\'][\'transForeignTable\']';
951 }
952 if (!empty($tableDefinition['ctrl']['transOrigPointerTable'])) {
953 unset($tableDefinition['ctrl']['transOrigPointerTable']);
954 $this->messages[] = 'The TCA setting \'transOrigPointerTable\' was removed '
955 . 'in TCA ' . $table . '[\'ctrl\'][\'transOrigPointerTable\']';
956 }
957 }
958 return $tca;
959 }
960
961 /**
962 * Removes "noCopy" from possible settings for "l10n_mode" for each column.
963 *
964 * @param array $tca
965 * @return array Migrated TCA
966 */
967 protected function migrateL10nModeDefinitions(array $tca)
968 {
969 foreach ($tca as $table => &$tableDefinition) {
970 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
971 continue;
972 }
973 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
974 if (empty($fieldConfig['l10n_mode'])) {
975 continue;
976 }
977 if ($fieldConfig['l10n_mode'] === 'noCopy') {
978 unset($fieldConfig['l10n_mode']);
979 $this->messages[] = 'The TCA setting \'noCopy\' was removed '
980 . 'in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']';
981 }
982 if ($fieldConfig['l10n_mode'] === 'mergeIfNotBlank') {
983 unset($fieldConfig['l10n_mode']);
984 if (empty($fieldConfig['config']['behaviour']['allowLanguageSynchronization'])) {
985 $fieldConfig['config']['behaviour']['allowLanguageSynchronization'] = true;
986 }
987 $this->messages[] = 'The TCA setting \'mergeIfNotBlank\' was removed '
988 . 'in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']'
989 . ' and changed to ' . $table . '[\'columns\'][\'' . $fieldName . '\']'
990 . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\'] = true';
991 }
992 }
993 }
994 return $tca;
995 }
996
997 /**
998 * Migrates localization definitions such as "allowLanguageSynchronization"
999 * or "l10n_mode" for tables pages and pages_language_overlay.
1000 *
1001 * @param array $tca
1002 * @return array Migrated TCA
1003 */
1004 protected function migratePageLocalizationDefinitions(array $tca)
1005 {
1006 if (
1007 empty($tca['pages_language_overlay']['columns'])
1008 ) {
1009 return $tca;
1010 }
1011
1012 // ensure, that localization settings are defined for
1013 // pages and not for pages_language_overlay
1014 foreach ($tca['pages_language_overlay']['columns'] as $fieldName => &$fieldConfig) {
1015 $l10nMode = $fieldConfig['l10n_mode'] ?? null;
1016 $allowLanguageSynchronization = $fieldConfig['config']['behaviour']['allowLanguageSynchronization'] ?? null;
1017
1018 $oppositeFieldConfig = $tca['pages']['columns'][$fieldName] ?? [];
1019 $oppositeL10nMode = $oppositeFieldConfig['l10n_mode'] ?? null;
1020 $oppositeAllowLanguageSynchronization = $oppositeFieldConfig['config']['behaviour']['allowLanguageSynchronization'] ?? null;
1021
1022 if ($l10nMode !== null) {
1023 if (!empty($oppositeFieldConfig) && $oppositeL10nMode !== 'exclude') {
1024 $tca['pages']['columns'][$fieldName]['l10n_mode'] = $l10nMode;
1025 $this->messages[] = 'The TCA setting \'l10n_mode\' was migrated '
1026 . 'to TCA pages[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\'] '
1027 . 'from TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']';
1028 }
1029 }
1030
1031 if (!empty($allowLanguageSynchronization) && empty($oppositeAllowLanguageSynchronization)) {
1032 $tca['pages']['columns'][$fieldName]['config']['behaviour']['allowLanguageSynchronization'] = (bool)$allowLanguageSynchronization;
1033 $this->messages[] = 'The TCA setting \'allowLanguageSynchronization\' was migrated '
1034 . 'to TCA pages[\'columns\'][\'' . $fieldName . '\']'
1035 . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\'] '
1036 . 'from TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\']'
1037 . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\']';
1038 }
1039 }
1040
1041 return $tca;
1042 }
1043
1044 /**
1045 * Removes "localizationMode" set to "keep" if used in combination with
1046 * "allowLanguageSynchronization" - in general "localizationMode" is
1047 * deprecated since TYPO3 CMS 8 and will be removed in TYPO3 CMS 9.
1048 *
1049 * @param array $tca
1050 * @return array
1051 */
1052 protected function migrateInlineLocalizationMode(array $tca)
1053 {
1054 foreach ($tca as $table => &$tableDefinition) {
1055 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
1056 continue;
1057 }
1058 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1059 if (($fieldConfig['config']['type'] ?? null) !== 'inline') {
1060 continue;
1061 }
1062
1063 $inlineLocalizationMode = ($fieldConfig['config']['behaviour']['localizationMode'] ?? null);
1064 if ($inlineLocalizationMode === null) {
1065 continue;
1066 }
1067
1068 $allowLanguageSynchronization = ($fieldConfig['config']['behaviour']['allowLanguageSynchronization'] ?? null);
1069 if ($inlineLocalizationMode === 'keep' && $allowLanguageSynchronization) {
1070 unset($fieldConfig['config']['behaviour']['localizationMode']);
1071 $this->messages[] = 'The TCA setting \'localizationMode\' is counter-productive '
1072 . ' if being used in combination with \'allowLanguageSynchronization\' and '
1073 . ' thus has been removed from TCA for ' . $table . '[\'columns\']'
1074 . '[\'' . $fieldName . '\'][\'config\'][\'behaviour\'][\'localizationMode\']';
1075 } else {
1076 $this->messages[] = 'The TCA setting \'localizationMode\' is deprecated '
1077 . ' and should be removed from TCA for ' . $table . '[\'columns\']'
1078 . '[\'' . $fieldName . '\'][\'config\'][\'behaviour\'][\'localizationMode\']';
1079 }
1080 }
1081 }
1082 return $tca;
1083 }
1084
1085 /**
1086 * Move ['ctrl']['requestUpdate'] to 'onChange => "reload"' of single fields
1087 *
1088 * @param array $tca Incoming TCA
1089 * @return array Migrated TCA
1090 */
1091 protected function migrateRequestUpdate(array $tca): array
1092 {
1093 foreach ($tca as $table => &$tableDefinition) {
1094 if (!empty($tableDefinition['ctrl']['requestUpdate'])) {
1095 $fields = GeneralUtility::trimExplode(',', $tableDefinition['ctrl']['requestUpdate']);
1096 foreach ($fields as $field) {
1097 if (isset($tableDefinition['columns'][$field])) {
1098 $tableDefinition['columns'][$field]['onChange'] = 'reload';
1099 }
1100 }
1101 $this->messages[] = 'The TCA setting [\'ctrl\'][\'requestUpdate\'] was removed from '
1102 . ' table ' . $table . '. The column field(s) "' . implode('" and "', $fields) . '" were updated'
1103 . ' and contain option "\'onChange\' => \'reload\'" parallel to \'config\' and \'label\' section.';
1104 unset($tableDefinition['ctrl']['requestUpdate']);
1105 }
1106 }
1107 return $tca;
1108 }
1109
1110 /**
1111 * Move all type=input with eval=date/time configuration to an own renderType
1112 *
1113 * @param array $tca
1114 * @return array Migrated TCA
1115 */
1116 protected function migrateInputDateTimeToRenderType(array $tca): array
1117 {
1118 foreach ($tca as $table => &$tableDefinition) {
1119 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
1120 continue;
1121 }
1122 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1123 if ($fieldConfig['config']['type'] !== 'input') {
1124 continue;
1125 }
1126 $eval = $fieldConfig['config']['eval'] ?? '';
1127 $eval = GeneralUtility::trimExplode(',', $eval, true);
1128 if (in_array('date', $eval, true)
1129 || in_array('datetime', $eval, true)
1130 || in_array('time', $eval, true)
1131 || in_array('timesec', $eval, true)
1132 ) {
1133 if (!isset($fieldConfig['config']['renderType'])) {
1134 $fieldConfig['config']['renderType'] = 'inputDateTime';
1135 $this->messages[] = 'The TCA setting \'renderType\' => \'inputDateTime\' was added '
1136 . 'in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
1137 }
1138 }
1139 }
1140 }
1141 return $tca;
1142 }
1143
1144 /**
1145 * Wizards configuration may hold "enableByTypeConfig" and are then enabled
1146 * for certain types via "defaultExtras".
1147 * Find wizards configured like that and migrate them to "columnsOverrides"
1148 *
1149 * @param array $tca Incoming TCA
1150 * @return array Migrated TCA
1151 */
1152 public function migrateWizardEnableByTypeConfigToColumnsOverrides(array $tca): array
1153 {
1154 $newTca = $tca;
1155 foreach ($tca as $table => $tableDefinition) {
1156 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
1157 continue;
1158 }
1159 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
1160 if (
1161 !empty($fieldConfig['config']['type']) // type is set
1162 && isset($fieldConfig['config']['wizards'])
1163 && is_array($fieldConfig['config']['wizards']) // and there are wizards
1164 ) {
1165 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1166 if (isset($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is given
1167 && $wizardConfig['enableByTypeConfig'] // and enabled
1168 ) { // and enableByTypeConfig is enabled
1169 // Remove this "enableByTypeConfig" wizard from columns
1170 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
1171 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
1172 // No type definition at all ... continue directly
1173 continue;
1174 }
1175 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
1176 if (empty($typeArray['columnsOverrides'][$fieldName]['defaultExtras'])
1177 || strpos($typeArray['columnsOverrides'][$fieldName]['defaultExtras'], $wizardName) === false
1178 ) {
1179 // Continue directly if this wizard is not enabled for given type
1180 continue;
1181 }
1182 $defaultExtras = $typeArray['columnsOverrides'][$fieldName]['defaultExtras'];
1183 $defaultExtrasArray = GeneralUtility::trimExplode(':', $defaultExtras, true);
1184 $newDefaultExtrasArray = [];
1185 foreach ($defaultExtrasArray as $fieldExtraField) {
1186 if (substr($fieldExtraField, 0, 8) === 'wizards[') {
1187 $enabledWizards = substr($fieldExtraField, 8, strlen($fieldExtraField) - 8); // Cut off "wizards[
1188 $enabledWizards = substr($enabledWizards, 0, strlen($enabledWizards) - 1);
1189 $enabledWizardsArray = GeneralUtility::trimExplode('|', $enabledWizards, true);
1190 foreach ($enabledWizardsArray as $enabledWizardName) {
1191 if ($enabledWizardName === $wizardName) {
1192 // Fill new array
1193 unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras']);
1194 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['wizards'][$enabledWizardName] = $wizardConfig;
1195 unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['wizards'][$enabledWizardName]['enableByTypeConfig']);
1196 $this->messages[] = 'The wizard with "enableByTypeConfig" set to 1 has been migrated to \'columnsOverrides\'.'
1197 . ' It has been migrated from "'
1198 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']" to '
1199 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\'].';
1200 }
1201 }
1202 } else {
1203 $newDefaultExtrasArray[] = $fieldExtraField;
1204 }
1205 }
1206 if ($defaultExtrasArray !== $newDefaultExtrasArray
1207 && !empty($newDefaultExtrasArray)
1208 ) {
1209 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras'] = implode(':', $newDefaultExtrasArray);
1210 }
1211 }
1212 } elseif (isset($wizardConfig['enableByTypeConfig'])) {
1213 // enableByTypeConfig is set, but not true or 1 or '1', just delete it.
1214 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]['enableByTypeConfig']);
1215 }
1216 }
1217 }
1218 }
1219 }
1220 return $newTca;
1221 }
1222
1223 /**
1224 * Migrates fields having a colorpicker wizard to a color field
1225 *
1226 * @param array $tca Incoming TCA
1227 * @return array Migrated TCA
1228 */
1229 protected function migrateColorPickerWizardToRenderType(array $tca): array
1230 {
1231 foreach ($tca as $table => &$tableDefinition) {
1232 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1233 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1234 if (isset($fieldConfig['config'])) {
1235 // Do not handle field where the render type is set.
1236 if (!empty($fieldConfig['config']['renderType'])) {
1237 continue;
1238 }
1239 if ($fieldConfig['config']['type'] === 'input') {
1240 if (isset($fieldConfig['config']['wizards']) && is_array($fieldConfig['config']['wizards'])) {
1241 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizard) {
1242 if (isset($wizard['type']) && ($wizard['type'] === 'colorbox')) {
1243 unset($fieldConfig['config']['wizards'][$wizardName]);
1244 if (empty($fieldConfig['config']['wizards'])) {
1245 unset($fieldConfig['config']['wizards']);
1246 }
1247 $fieldConfig['config']['renderType'] = 'colorpicker';
1248 $this->messages[] = 'The color-picker wizard using \'colorbox\' is deprecated'
1249 . ' in TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
1250 . '[\'wizards\'][\'' . $wizardName . '\'] and was changed to ' . $table
1251 . '[\'columns\'][\'' . $fieldName . '\'][\'config\'] = \'colorpicker\'';
1252 }
1253 }
1254 }
1255 if (empty($fieldConfig['config']['wizards'])) {
1256 unset($fieldConfig['config']['wizards']);
1257 }
1258 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1259 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1260 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1261 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1262 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1263 ) {
1264 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1265 if (isset($wizard['type']) && ($wizard['type'] === 'colorbox')) {
1266 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1267 $typeArray['columnsOverrides'][$fieldName]['config']['type'] = 'input';
1268 $typeArray['columnsOverrides'][$fieldName]['config']['renderType'] = 'colorpicker';
1269 $this->messages[] = 'The color-picker wizard in columnsOverrides using \'colorbox\' has been migrated to a \'rendertype\' = \'colorpicker\'.'
1270 . ' It has been migrated from TCA "' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1271 . '[\'wizards\'][\'' . $wizardName . '\'][\'type\'] = \'colorbox\'"" to "' . $table
1272 . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'renderType\'] = \'colorpicker\'"';
1273 }
1274 }
1275 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1276 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1277 }
1278 }
1279 }
1280 }
1281 }
1282 }
1283 }
1284 }
1285 }
1286 }
1287
1288 return $tca;
1289 }
1290
1291 /**
1292 * Move type=input with select wizard to config['valuePicker']
1293 *
1294 * @param array $tca
1295 * @return array Migrated TCA
1296 */
1297 protected function migrateSelectWizardToValuePicker(array $tca): array
1298 {
1299 foreach ($tca as $table => &$tableDefinition) {
1300 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1301 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1302 if ($fieldConfig['config']['type'] === 'input' || $fieldConfig['config']['type'] === 'text') {
1303 if (isset($fieldConfig['config']['wizards']) && is_array($fieldConfig['config']['wizards'])) {
1304 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1305 if (isset($wizardConfig['type'])
1306 && $wizardConfig['type'] === 'select'
1307 && isset($wizardConfig['items'])
1308 && is_array($wizardConfig['items'])
1309 ) {
1310 $fieldConfig['config']['valuePicker']['items'] = $wizardConfig['items'];
1311 if (isset($wizardConfig['mode'])
1312 && is_string($wizardConfig['mode'])
1313 && in_array($wizardConfig['mode'], ['append', 'prepend', ''])
1314 ) {
1315 $fieldConfig['config']['valuePicker']['mode'] = $wizardConfig['mode'];
1316 }
1317 unset($fieldConfig['config']['wizards'][$wizardName]);
1318 $this->messages[] = 'The select wizard in TCA '
1319 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
1320 . ' has been migrated to '
1321 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'valuePicker\'].';
1322 }
1323 }
1324 }
1325 if (empty($fieldConfig['config']['wizards'])) {
1326 unset($fieldConfig['config']['wizards']);
1327 }
1328 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1329 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1330 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1331 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1332 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1333 ) {
1334 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1335 if (isset($wizard['type'])
1336 && ($wizard['type'] === 'select')
1337 && isset($wizard['items'])
1338 && is_array($wizard['items'])
1339 ) {
1340 $typeArray['columnsOverrides'][$fieldName]['config']['valuePicker'] = $wizard;
1341 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1342 unset($typeArray['columnsOverrides'][$fieldName]['config']['valuePicker']['type']);
1343 $this->messages[] = 'The select wizard in columnsOverrides using \'type\' = \'select\' has been migrated'
1344 . ' from TCA ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1345 . '[\'wizards\'][\'' . $wizardName . '\'] to ' . $table
1346 . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'valuePicker\']';
1347 }
1348 }
1349 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1350 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1351 }
1352 }
1353 }
1354 }
1355 }
1356 }
1357 }
1358 }
1359 }
1360 return $tca;
1361 }
1362
1363 /**
1364 * Move type=input with select wizard to config['valuePicker']
1365 *
1366 * @param array $tca
1367 * @return array Migrated TCA
1368 */
1369 protected function migrateSliderWizardToSliderConfiguration(array $tca): array
1370 {
1371 foreach ($tca as $table => &$tableDefinition) {
1372 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1373 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1374 if ($fieldConfig['config']['type'] === 'input') {
1375 if (isset($fieldConfig['config']['wizards'])
1376 && is_array($fieldConfig['config']['wizards'])) {
1377 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1378 if (isset($wizardConfig['type']) && $wizardConfig['type'] === 'slider') {
1379 $fieldConfig['config']['slider'] = [];
1380 if (isset($wizardConfig['width'])) {
1381 $fieldConfig['config']['slider']['width'] = $wizardConfig['width'];
1382 }
1383 if (isset($wizardConfig['step'])) {
1384 $fieldConfig['config']['slider']['step'] = $wizardConfig['step'];
1385 }
1386 unset($fieldConfig['config']['wizards'][$wizardName]);
1387 $this->messages[] = 'The slider wizard in TCA '
1388 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
1389 . ' has been migrated to '
1390 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'slider\'].';
1391 }
1392 }
1393 }
1394 if (empty($fieldConfig['config']['wizards'])) {
1395 unset($fieldConfig['config']['wizards']);
1396 }
1397 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1398 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1399 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1400 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1401 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1402 ) {
1403 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1404 if (isset($wizard['type']) && ($wizard['type'] === 'slider')) {
1405 $typeArray['columnsOverrides'][$fieldName]['config']['slider'] = $wizard;
1406 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1407 unset($typeArray['columnsOverrides'][$fieldName]['config']['slider']['type']);
1408 $this->messages[] = 'The slider wizard in columnsOverrides using \'type\' = \'slider\' has been migrated'
1409 . ' from TCA ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1410 . '[\'wizards\'][\'' . $wizardName . '\'] to ' . $table
1411 . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'slider\']';
1412 }
1413 }
1414 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1415 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1416 }
1417 }
1418 }
1419 }
1420 }
1421 }
1422 }
1423 }
1424 }
1425 return $tca;
1426 }
1427
1428 /**
1429 * Move type=input fields that have a "link" wizard to an own renderType with fieldControl
1430 *
1431 * @param array $tca
1432 * @return array Modified TCA
1433 */
1434 protected function migrateLinkWizardToRenderTypeAndFieldControl(array $tca): array
1435 {
1436 foreach ($tca as $table => &$tableDefinition) {
1437 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1438 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1439 if ($fieldConfig['config']['type'] === 'input'
1440 && !isset($fieldConfig['config']['renderType'])
1441 ) {
1442 if (isset($fieldConfig['config']['wizards'])
1443 && is_array($fieldConfig['config']['wizards'])) {
1444 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1445 if (isset($wizardConfig['type'])
1446 && $wizardConfig['type'] === 'popup'
1447 && isset($wizardConfig['module']['name'])
1448 && $wizardConfig['module']['name'] === 'wizard_link'
1449 ) {
1450 $fieldConfig['config']['renderType'] = 'inputLink';
1451 if (isset($wizardConfig['title'])) {
1452 $fieldConfig['config']['fieldControl']['linkPopup']['options']['title'] = $wizardConfig['title'];
1453 }
1454 if (isset($wizardConfig['JSopenParams'])) {
1455 $fieldConfig['config']['fieldControl']['linkPopup']['options']['windowOpenParameters']
1456 = $wizardConfig['JSopenParams'];
1457 }
1458 if (isset($wizardConfig['params']['blindLinkOptions'])) {
1459 $fieldConfig['config']['fieldControl']['linkPopup']['options']['blindLinkOptions']
1460 = $wizardConfig['params']['blindLinkOptions'];
1461 }
1462 if (isset($wizardConfig['params']['blindLinkFields'])) {
1463 $fieldConfig['config']['fieldControl']['linkPopup']['options']['blindLinkFields']
1464 = $wizardConfig['params']['blindLinkFields'];
1465 }
1466 if (isset($wizardConfig['params']['allowedExtensions'])) {
1467 $fieldConfig['config']['fieldControl']['linkPopup']['options']['allowedExtensions']
1468 = $wizardConfig['params']['allowedExtensions'];
1469 }
1470 unset($fieldConfig['config']['wizards'][$wizardName]);
1471 $this->messages[] = 'The link wizard has been migrated to a \'renderType\' => \'inputLink \'. '
1472 . 'It has been migrated from TCA table "'
1473 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']" to "'
1474 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'renderType\'] = \'inputLink\'".';
1475 }
1476 }
1477 }
1478 if (empty($fieldConfig['config']['wizards'])) {
1479 unset($fieldConfig['config']['wizards']);
1480 }
1481 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1482 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1483 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1484 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1485 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1486 ) {
1487 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1488 if (isset($wizard['type'])
1489 && $wizard['type'] === 'popup'
1490 && isset($wizard['module']['name'])
1491 && $wizard['module']['name'] === 'wizard_link'
1492 ) {
1493 $typeArray['columnsOverrides'][$fieldName]['config']['renderType'] = 'inputLink';
1494 if (isset($wizard['title'])) {
1495 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['linkPopup']['options']['title'] = $wizard['title'];
1496 }
1497 if (isset($wizard['JSopenParams'])) {
1498 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['linkPopup']['options']['windowOpenParameters']
1499 = $wizard['JSopenParams'];
1500 }
1501 if (isset($wizard['params']['blindLinkOptions'])) {
1502 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['linkPopup']['options']['blindLinkOptions']
1503 = $wizard['params']['blindLinkOptions'];
1504 }
1505 if (isset($wizard['params']['blindLinkFields'])) {
1506 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['linkPopup']['options']['blindLinkFields']
1507 = $wizard['params']['blindLinkFields'];
1508 }
1509 if (isset($wizard['params']['allowedExtensions'])) {
1510 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['linkPopup']['options']['allowedExtensions']
1511 = $wizard['params']['allowedExtensions'];
1512 }
1513 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1514 $this->messages[] = 'The link wizard in columnsOverrides using \'type\' = \'popup\' has been migrated to a \'renderType\' = \'inputLink\'.'
1515 . ' It has been migrated from TCA "' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1516 . '[\'wizards\'][\'' . $wizardName . '\']" to "' . $table
1517 . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'renderType\'] = \'inputLink\'"';
1518 }
1519 }
1520 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1521 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1522 }
1523 }
1524 }
1525 }
1526 }
1527 }
1528 }
1529 }
1530 }
1531
1532 return $tca;
1533 }
1534
1535 /**
1536 * Find select and group fields with enabled edit wizard and migrate to "fieldControl"
1537 *
1538 * @param array $tca
1539 * @return array
1540 */
1541 protected function migrateEditWizardToFieldControl(array $tca): array
1542 {
1543 foreach ($tca as $table => &$tableDefinition) {
1544 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1545 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1546 if ($fieldConfig['config']['type'] === 'group'
1547 || $fieldConfig['config']['type'] === 'select'
1548 ) {
1549 if (isset($fieldConfig['config']['wizards'])
1550 && is_array($fieldConfig['config']['wizards'])
1551 ) {
1552 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1553 if (isset($wizardConfig['type'])
1554 && $wizardConfig['type'] === 'popup'
1555 && isset($wizardConfig['module']['name'])
1556 && $wizardConfig['module']['name'] === 'wizard_edit'
1557 && !isset($fieldConfig['config']['fieldControl']['editPopup'])
1558 ) {
1559 $fieldConfig['config']['fieldControl']['editPopup']['disabled'] = false;
1560 if (isset($wizardConfig['title'])) {
1561 $fieldConfig['config']['fieldControl']['editPopup']['options']['title'] = $wizardConfig['title'];
1562 }
1563 if (isset($wizardConfig['JSopenParams'])) {
1564 $fieldConfig['config']['fieldControl']['editPopup']['options']['windowOpenParameters']
1565 = $wizardConfig['JSopenParams'];
1566 }
1567 unset($fieldConfig['config']['wizards'][$wizardName]);
1568 $this->messages[] = 'The edit wizard in TCA has been migrated to a \'fieldControl\' = \'editPopup\' element.'
1569 . ' It has been migrated from TCA "'
1570 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']" to "'
1571 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldControl\']=\'editPopup\'".';
1572 }
1573 }
1574 }
1575 if (empty($fieldConfig['config']['wizards'])) {
1576 unset($fieldConfig['config']['wizards']);
1577 }
1578 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1579 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1580 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1581 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1582 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1583 ) {
1584 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1585 if (isset($wizard['type'])
1586 && $wizard['type'] === 'popup'
1587 && isset($wizard['module']['name'])
1588 && $wizard['module']['name'] === 'wizard_edit'
1589 ) {
1590 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['editPopup']['disabled'] = false;
1591 if (isset($wizard['title'])) {
1592 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['editPopup']['options']['title']
1593 = $wizard['title'];
1594 }
1595 if (isset($wizard['JSopenParams'])) {
1596 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['editPopup']['options']['windowOpenParameters']
1597 = $wizard['JSopenParams'];
1598 }
1599 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1600 $this->messages[] = 'The edit wizard in columnsOverrides using \'type\' = \'popup\' has been migrated to a \'fieldControl\' = \'editPopup\' element.'
1601 . ' It has been migrated from TCA "'
1602 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1603 . '[\'wizards\'][\'' . $wizardName . '\']" , to "'
1604 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'fieldControl\']=\'editPopup\'".';
1605 }
1606 }
1607 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1608 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1609 }
1610 }
1611 }
1612 }
1613 }
1614 }
1615 }
1616 }
1617 }
1618
1619 return $tca;
1620 }
1621
1622 /**
1623 * Find select and group fields with enabled add wizard and migrate to "fieldControl"
1624 *
1625 * @param array $tca
1626 * @return array
1627 */
1628 protected function migrateAddWizardToFieldControl(array $tca): array
1629 {
1630 foreach ($tca as $table => &$tableDefinition) {
1631 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1632 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1633 if ($fieldConfig['config']['type'] === 'group'
1634 || $fieldConfig['config']['type'] === 'select'
1635 ) {
1636 if (isset($fieldConfig['config']['wizards'])
1637 && is_array($fieldConfig['config']['wizards'])
1638 ) {
1639 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1640 if (isset($wizardConfig['type'])
1641 && $wizardConfig['type'] === 'script'
1642 && isset($wizardConfig['module']['name'])
1643 && $wizardConfig['module']['name'] === 'wizard_add'
1644 && !isset($fieldConfig['config']['fieldControl']['addRecord'])
1645 ) {
1646 $fieldConfig['config']['fieldControl']['addRecord']['disabled'] = false;
1647 if (isset($wizardConfig['title'])) {
1648 $fieldConfig['config']['fieldControl']['addRecord']['options']['title'] = $wizardConfig['title'];
1649 }
1650 if (isset($wizardConfig['params']['table'])) {
1651 $fieldConfig['config']['fieldControl']['addRecord']['options']['table']
1652 = $wizardConfig['params']['table'];
1653 }
1654 if (isset($wizardConfig['params']['pid'])) {
1655 $fieldConfig['config']['fieldControl']['addRecord']['options']['pid']
1656 = $wizardConfig['params']['pid'];
1657 }
1658 if (isset($wizardConfig['params']['setValue'])) {
1659 $fieldConfig['config']['fieldControl']['addRecord']['options']['setValue']
1660 = $wizardConfig['params']['setValue'];
1661 }
1662 unset($fieldConfig['config']['wizards'][$wizardName]);
1663 $this->messages[] = 'The add wizard in TCA has been migrated to a \'fieldControl\' = \'addRecord\' element.'
1664 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
1665 . ' It has been migrated from TCA "'
1666 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldControl\']=\'addRecord\'.';
1667 }
1668 }
1669 }
1670 if (empty($fieldConfig['config']['wizards'])) {
1671 unset($fieldConfig['config']['wizards']);
1672 }
1673 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1674 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1675 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1676 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1677 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1678 ) {
1679 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1680 if (isset($wizard['type'])
1681 && $wizard['type'] === 'script'
1682 && isset($wizard['module']['name'])
1683 && $wizard['module']['name'] === 'wizard_add'
1684 ) {
1685 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['addRecord']['disabled'] = false;
1686 if (isset($wizard['title'])) {
1687 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['addRecord']['options']['title']
1688 = $wizard['title'];
1689 }
1690 if (isset($wizard['params']['table'])) {
1691 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['addRecord']['options']['table']
1692 = $wizard['params']['table'];
1693 }
1694 if (isset($wizard['params']['pid'])) {
1695 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['addRecord']['options']['pid']
1696 = $wizard['params']['pid'];
1697 }
1698 if (isset($wizard['params']['setValue'])) {
1699 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['addRecord']['options']['setValue']
1700 = $wizard['params']['setValue'];
1701 }
1702 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1703 $this->messages[] = 'The add wizard in columnsOverrides using \'type\' = \'script\' has been migrated to a \'fieldControl\' = \'addRecord\' element.'
1704 . ' It has been migrated from TCA "'
1705 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1706 . '[\'wizards\'][\'' . $wizardName . '\']" to "'
1707 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'fieldControl\'=\'addRecord\'".';
1708 }
1709 }
1710 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1711 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1712 }
1713 }
1714 }
1715 }
1716 }
1717 }
1718 }
1719 }
1720 }
1721
1722 return $tca;
1723 }
1724
1725 /**
1726 * Find select and group fields with enabled list wizard and migrate to "fieldControl"
1727 *
1728 * @param array $tca
1729 * @return array
1730 */
1731 protected function migrateListWizardToFieldControl(array $tca): array
1732 {
1733 foreach ($tca as $table => &$tableDefinition) {
1734 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1735 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1736 if ($fieldConfig['config']['type'] === 'group'
1737 || $fieldConfig['config']['type'] === 'select'
1738 ) {
1739 if (isset($fieldConfig['config']['wizards'])
1740 && is_array($fieldConfig['config']['wizards'])
1741 ) {
1742 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1743 if (isset($wizardConfig['type'])
1744 && $wizardConfig['type'] === 'script'
1745 && isset($wizardConfig['module']['name'])
1746 && $wizardConfig['module']['name'] === 'wizard_list'
1747 && !isset($fieldConfig['config']['fieldControl']['listModule'])
1748 ) {
1749 $fieldConfig['config']['fieldControl']['listModule']['disabled'] = false;
1750 if (isset($wizardConfig['title'])) {
1751 $fieldConfig['config']['fieldControl']['listModule']['options']['title'] = $wizardConfig['title'];
1752 }
1753 if (isset($wizardConfig['params']['table'])) {
1754 $fieldConfig['config']['fieldControl']['listModule']['options']['table']
1755 = $wizardConfig['params']['table'];
1756 }
1757 if (isset($wizardConfig['params']['pid'])) {
1758 $fieldConfig['config']['fieldControl']['listModule']['options']['pid']
1759 = $wizardConfig['params']['pid'];
1760 }
1761 unset($fieldConfig['config']['wizards'][$wizardName]);
1762 $this->messages[] = 'The list wizard in TCA has been migrated to a \'fieldControl\' = \'listModule\' element.'
1763 . ' It has been migrated from TCA "'
1764 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
1765 . '" to "'
1766 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldControl\'=\'listModule\'".';
1767 }
1768 }
1769 }
1770 if (empty($fieldConfig['config']['wizards'])) {
1771 unset($fieldConfig['config']['wizards']);
1772 }
1773 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1774 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1775 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1776 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1777 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1778 ) {
1779 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1780 if (isset($wizard['type'])
1781 && $wizard['type'] === 'script'
1782 && isset($wizard['module']['name'])
1783 && $wizard['module']['name'] === 'wizard_list'
1784 ) {
1785 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['listModule']['disabled'] = false;
1786 if (isset($wizard['title'])) {
1787 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['listModule']['options']['title']
1788 = $wizard['title'];
1789 }
1790 if (isset($wizard['params']['table'])) {
1791 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['listModule']['options']['table']
1792 = $wizard['params']['table'];
1793 }
1794 if (isset($wizard['params']['pid'])) {
1795 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['listModule']['options']['pid']
1796 = $wizard['params']['pid'];
1797 }
1798 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1799 $this->messages[] = 'The list wizard in columnsOverrides using \'type\' = \'script\' has been migrated to a \'fieldControl\' = \'listModule\' element.'
1800 . ' It has been migrated from TCA "'
1801 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1802 . '[\'wizards\'][\'' . $wizardName . '\']" to "'
1803 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'fieldControl\'=\'listModule\'".';
1804 }
1805 }
1806 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1807 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1808 }
1809 }
1810 }
1811 }
1812 }
1813 }
1814 }
1815 }
1816 }
1817
1818 return $tca;
1819 }
1820
1821 /**
1822 * Migrate defaultExtras "nowrap", "enable-tab", "fixed-font". Then drop all
1823 * remaining "defaultExtras", there shouldn't exist anymore.
1824 *
1825 * @param array $tca
1826 * @return array
1827 */
1828 protected function migrateLastPiecesOfDefaultExtras(array $tca): array
1829 {
1830 foreach ($tca as $table => &$tableDefinition) {
1831 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1832 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1833 if (isset($fieldConfig['defaultExtras'])) {
1834 $defaultExtrasArray = GeneralUtility::trimExplode(':', $fieldConfig['defaultExtras'], true);
1835 foreach ($defaultExtrasArray as $defaultExtrasSetting) {
1836 if ($defaultExtrasSetting === 'rte_only') {
1837 $this->messages[] = 'The defaultExtras setting \'rte_only\' in TCA table '
1838 . $table . '[\'columns\'][\'' . $fieldName . '\'] has been dropped, the setting'
1839 . ' is no longer supported';
1840 continue;
1841 }
1842 if ($defaultExtrasSetting === 'nowrap') {
1843 $fieldConfig['config']['wrap'] = 'off';
1844 $this->messages[] = 'The defaultExtras setting \'nowrap\' in TCA table '
1845 . $table . '[\'columns\'][\'' . $fieldName . '\'] has been migrated to TCA table '
1846 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wrap\'] = \'off\'';
1847 } elseif ($defaultExtrasSetting === 'enable-tab') {
1848 $fieldConfig['config']['enableTabulator'] = true;
1849 $this->messages[] = 'The defaultExtras setting \'enable-tab\' in TCA table '
1850 . $table . '[\'columns\'][\'' . $fieldName . '\'] has been migrated to TCA table '
1851 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'enableTabulator\'] = true';
1852 } elseif ($defaultExtrasSetting === 'fixed-font') {
1853 $fieldConfig['config']['fixedFont'] = true;
1854 $this->messages[] = 'The defaultExtras setting \'fixed-font\' in TCA table '
1855 . $table . '[\'columns\'][\'' . $fieldName . '\'] has been migrated to TCA table '
1856 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fixedFont\'] = true';
1857 } else {
1858 $this->messages[] = 'The defaultExtras setting \'' . $defaultExtrasSetting . '\' in TCA table '
1859 . $table . '[\'columns\'][\'' . $fieldName . '\'] is unknown and has been dropped.';
1860 }
1861 }
1862 unset($fieldConfig['defaultExtras']);
1863 }
1864 }
1865 }
1866 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1867 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1868 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1869 foreach ($typeArray['columnsOverrides'] as $fieldName => &$overrideConfig) {
1870 if (!isset($overrideConfig['defaultExtras'])) {
1871 continue;
1872 }
1873 $defaultExtrasArray = GeneralUtility::trimExplode(':', $overrideConfig['defaultExtras'], true);
1874 foreach ($defaultExtrasArray as $defaultExtrasSetting) {
1875 if ($defaultExtrasSetting === 'rte_only') {
1876 $this->messages[] = 'The defaultExtras setting \'rte_only\' in TCA table '
1877 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\']'
1878 . ' has been dropped, the setting is no longer supported';
1879 continue;
1880 }
1881 if ($defaultExtrasSetting === 'nowrap') {
1882 $overrideConfig['config']['wrap'] = 'off';
1883 $this->messages[] = 'The defaultExtras setting \'nowrap\' in TCA table '
1884 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\']'
1885 . ' has been migrated to TCA table '
1886 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\'][\'config\'][\'wrap\'] = \'off\'';
1887 } elseif ($defaultExtrasSetting === 'enable-tab') {
1888 $overrideConfig['config']['enableTabulator'] = true;
1889 $this->messages[] = 'The defaultExtras setting \'enable-tab\' in TCA table '
1890 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\']'
1891 . ' has been migrated to TCA table '
1892 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\'][\'config\'][\'enableTabulator\'] = true';
1893 } elseif ($defaultExtrasSetting === 'fixed-font') {
1894 $overrideConfig['config']['fixedFont'] = true;
1895 $this->messages[] = 'The defaultExtras setting \'fixed-font\' in TCA table '
1896 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\']'
1897 . ' has been migrated to TCA table '
1898 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\'][\'config\'][\'fixedFont\'] = true';
1899 } else {
1900 $this->messages[] = 'The defaultExtras setting \'' . $defaultExtrasSetting . '\' in TCA table '
1901 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'' . $fieldName . '\']'
1902 . ' is unknown and has been dropped.';
1903 }
1904 }
1905 unset($overrideConfig['defaultExtras']);
1906 }
1907 }
1908 }
1909 }
1910 }
1911
1912 return $tca;
1913 }
1914
1915 /**
1916 * Migrate wizard_table script to renderType="textTable" with options in fieldControl
1917 *
1918 * @param array $tca
1919 * @return array
1920 */
1921 protected function migrateTableWizardToRenderType(array $tca): array
1922 {
1923 foreach ($tca as $table => &$tableDefinition) {
1924 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
1925 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
1926 if ($fieldConfig['config']['type'] === 'text') {
1927 if (isset($fieldConfig['config']['wizards'])
1928 && is_array($fieldConfig['config']['wizards'])
1929 ) {
1930 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
1931 if (isset($wizardConfig['type'])
1932 && $wizardConfig['type'] === 'script'
1933 && isset($wizardConfig['module']['name'])
1934 && $wizardConfig['module']['name'] === 'wizard_table'
1935 && !isset($fieldConfig['config']['fieldControl']['tableWizard'])
1936 && !isset($fieldConfig['config']['renderType'])
1937 ) {
1938 $fieldConfig['config']['renderType'] = 'textTable';
1939 if (isset($wizardConfig['title'])) {
1940 $fieldConfig['config']['fieldControl']['tableWizard']['options']['title'] = $wizardConfig['title'];
1941 }
1942 if (isset($wizardConfig['params']['xmlOutput']) && (int)$wizardConfig['params']['xmlOutput'] !== 0) {
1943 $fieldConfig['config']['fieldControl']['tableWizard']['options']['xmlOutput']
1944 = (int)$wizardConfig['params']['xmlOutput'];
1945 }
1946 if (isset($wizardConfig['params']['numNewRows'])) {
1947 $fieldConfig['config']['fieldControl']['tableWizard']['options']['numNewRows']
1948 = $wizardConfig['params']['numNewRows'];
1949 }
1950 unset($fieldConfig['config']['wizards'][$wizardName]);
1951 $this->messages[] = 'The table wizard in TCA has been migrated to a \'renderType\' = \'textTable\'.'
1952 . ' It has been migrated from TCA "'
1953 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
1954 . '" to "'
1955 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'renderType\'] = \'textTable\'".';
1956 }
1957 }
1958 }
1959 if (empty($fieldConfig['config']['wizards'])) {
1960 unset($fieldConfig['config']['wizards']);
1961 }
1962 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
1963 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
1964 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
1965 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1966 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
1967 ) {
1968 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
1969 if (isset($wizard['type'])
1970 && $wizard['type'] === 'script'
1971 && isset($wizard['module']['name'])
1972 && $wizard['module']['name'] === 'wizard_table'
1973 && !isset($typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['tableWizard'])
1974 && !isset($typeArray['columnsOverrides'][$fieldName]['config']['renderType'])
1975 ) {
1976 $typeArray['columnsOverrides'][$fieldName]['config']['renderType'] = 'textTable';
1977 if (isset($wizard['title'])) {
1978 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['tableWizard']['options']['title']
1979 = $wizard['title'];
1980 }
1981 if (isset($wizard['params']['xmlOutput']) && (int)$wizard['params']['xmlOutput'] !== 0) {
1982 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['tableWizard']['options']['xmlOutput']
1983 = (int)$wizard['params']['xmlOutput'];
1984 }
1985 if (isset($wizard['params']['numNewRows'])) {
1986 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['tableWizard']['options']['numNewRows']
1987 = $wizard['params']['numNewRows'];
1988 }
1989 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
1990 $this->messages[] = 'The table wizard in columnsOverrides using \'type\' = \'script\' has been migrated to a \'renderType\' = \'textTable\'.'
1991 . ' It has been migrated from TCA "'
1992 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
1993 . '[\'wizards\'][\'' . $wizardName . '\']" to "'
1994 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'renderType\'] = \'textTable\'".';
1995 }
1996 }
1997 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
1998 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
1999 }
2000 }
2001 }
2002 }
2003 }
2004 }
2005 }
2006 }
2007 }
2008
2009 return $tca;
2010 }
2011
2012 /**
2013 * Migrate "wizard_rte" wizards to rtehtmlarea fieldControl
2014 *
2015 * @param array $tca
2016 * @return array
2017 */
2018 protected function migrateFullScreenRichtextToFieldControl(array $tca): array
2019 {
2020 foreach ($tca as $table => &$tableDefinition) {
2021 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
2022 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
2023 if ($fieldConfig['config']['type'] === 'text') {
2024 if (isset($fieldConfig['config']['wizards'])
2025 && is_array($fieldConfig['config']['wizards'])
2026 ) {
2027 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
2028 if (isset($wizardConfig['type'])
2029 && $wizardConfig['type'] === 'script'
2030 && isset($wizardConfig['module']['name'])
2031 && $wizardConfig['module']['name'] === 'wizard_rte'
2032 && !isset($fieldConfig['config']['fieldControl']['fullScreenRichtext'])
2033 && isset($fieldConfig['config']['enableRichtext'])
2034 && (bool)$fieldConfig['config']['enableRichtext'] === true
2035 ) {
2036 // Field is configured for richtext, so enable the full screen wizard
2037 $fieldConfig['config']['fieldControl']['fullScreenRichtext']['disabled'] = false;
2038 if (isset($wizardConfig['title'])) {
2039 $fieldConfig['config']['fieldControl']['fullScreenRichtext']['options']['title'] = $wizardConfig['title'];
2040 }
2041 unset($fieldConfig['config']['wizards'][$wizardName]);
2042 $this->messages[] = 'The RTE fullscreen wizard in TCA has been migrated to a \'fieldControl\' = \'fullScreenRichtext\'.'
2043 . ' It has been migrated from TCA "'
2044 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
2045 . '" to "'
2046 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldControl\']=\'fullScreenRichtext\'".';
2047 } elseif (isset($wizardConfig['type'])
2048 && $wizardConfig['type'] === 'script'
2049 && isset($wizardConfig['module']['name'])
2050 && $wizardConfig['module']['name'] === 'wizard_rte'
2051 && !isset($fieldConfig['config']['fieldControl']['fullScreenRichtext'])
2052 && (
2053 !isset($fieldConfig['config']['enableRichtext'])
2054 || isset($fieldConfig['config']['enableRichtext']) && (bool)$fieldConfig['config']['enableRichtext'] === false
2055 )
2056 ) {
2057 // Wizard is given, but field is not configured for richtext
2058 // Find types that enableRichtext and enable full screen for those types
2059 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
2060 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
2061 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
2062 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['enableRichtext'])
2063 && (bool)$typeArray['columnsOverrides'][$fieldName]['config']['enableRichtext'] === true
2064 ) {
2065 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['fullScreenRichtext']['disabled'] = false;
2066 if (isset($wizardConfig['title'])) {
2067 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['fullScreenRichtext']['options']['title']
2068 = $wizardConfig['title'];
2069 }
2070 $this->messages[] = 'The RTE fullscreen wizard in TCA has been migrated to a \'fieldControl\' = \'fullScreenRichtext\'.'
2071 . ' It has been migrated from TCA "'
2072 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
2073 . '" to "'
2074 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'fieldControl\']=\'fullScreenRichtext\'';
2075 }
2076 }
2077 }
2078 }
2079 unset($fieldConfig['config']['wizards'][$wizardName]);
2080 }
2081 }
2082 }
2083 if (empty($fieldConfig['config']['wizards'])) {
2084 unset($fieldConfig['config']['wizards']);
2085 }
2086 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
2087 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
2088 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
2089 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
2090 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
2091 ) {
2092 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
2093 if (isset($wizard['type'])
2094 && $wizard['type'] === 'script'
2095 && isset($wizard['module']['name'])
2096 && $wizard['module']['name'] === 'wizard_rte'
2097 && !isset($typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['fullScreenRichtext'])
2098 ) {
2099 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['fullScreenRichtext']['disabled'] = false;
2100 if (isset($wizard['title'])) {
2101 $typeArray['columnsOverrides'][$fieldName]['config']['fieldControl']['fullScreenRichtext']['options']['title']
2102 = $wizard['title'];
2103 }
2104 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
2105 $this->messages[] = 'The RTE fullscreen wizard in columnsOverrides using \'type\' = \'script\' has been migrated to a \'fieldControl\' = \'fullScreenRichtext\'.'
2106 . ' It has been migrated from TCA "'
2107 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
2108 . '[\'wizards\'][\'' . $wizardName . '\']" to "'
2109 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'fieldControl\']=\'fullScreenRichtext\'".';
2110 }
2111 }
2112 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
2113 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
2114 }
2115 }
2116 }
2117 }
2118 }
2119 }
2120 }
2121 }
2122 }
2123
2124 return $tca;
2125 }
2126
2127 /**
2128 * Migrate the "suggest" wizard in type=group to "hideSuggest" and "suggestOptions"
2129 *
2130 * @param array $tca Given TCA
2131 * @return array Modified TCA
2132 */
2133 protected function migrateSuggestWizardTypeGroup(array $tca): array
2134 {
2135 foreach ($tca as $table => &$tableDefinition) {
2136 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
2137 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
2138 if ($fieldConfig['config']['type'] === 'group'
2139 && isset($fieldConfig['config']['internal_type'])
2140 && $fieldConfig['config']['internal_type'] === 'db'
2141 ) {
2142 if (isset($fieldConfig['config']['hideSuggest'])) {
2143 continue;
2144 }
2145 if (isset($fieldConfig['config']['wizards']) && is_array($fieldConfig['config']['wizards'])) {
2146 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
2147 if (isset($wizardConfig['type']) && $wizardConfig['type'] === 'suggest') {
2148 unset($wizardConfig['type']);
2149 if (!empty($wizardConfig)) {
2150 $fieldConfig['config']['suggestOptions'] = $wizardConfig;
2151 $this->messages[] = 'The suggest wizard options in TCA '
2152 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
2153 . ' have been migrated to '
2154 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'suggestOptions\'].';
2155 } else {
2156 $this->messages[] = 'The suggest wizard in TCA '
2157 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'wizards\'][\'' . $wizardName . '\']'
2158 . ' is enabled by default and has been removed.';
2159 }
2160 unset($fieldConfig['config']['wizards'][$wizardName]);
2161 }
2162 }
2163 }
2164 if (empty($fieldConfig['config']['wizards'])) {
2165 unset($fieldConfig['config']['wizards']);
2166 }
2167 if (isset($tableDefinition['types']) && is_array($tableDefinition['types'])) {
2168 foreach ($tableDefinition['types'] as $typeName => &$typeArray) {
2169 if (isset($typeArray['columnsOverrides']) && is_array($typeArray['columnsOverrides'])) {
2170 if (isset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
2171 && is_array($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])
2172 ) {
2173 foreach ($typeArray['columnsOverrides'][$fieldName]['config']['wizards'] as $wizardName => $wizard) {
2174 if (isset($wizard['type']) && $wizard['type'] === 'suggest'
2175 ) {
2176 unset($wizard['type']);
2177 $fieldConfig['config']['hideSuggest'] = true;
2178 $typeArray['columnsOverrides'][$fieldName]['config']['hideSuggest'] = false;
2179 if (!empty($wizard)) {
2180 $typeArray['columnsOverrides'][$fieldName]['config']['suggestOptions'] = $wizard;
2181 $this->messages[] = 'The suggest wizard options in columnsOverrides have been migrated'
2182 . ' from TCA ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
2183 . '[\'wizards\'][\'' . $wizardName . '\'] to \'suggestOptions\' in '
2184 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']';
2185 } else {
2186 $this->messages[] = 'The suggest wizard in columnsOverrides has been migrated'
2187 . ' from TCA ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\']'
2188 . '[\'wizards\'][\'' . $wizardName . '\'] to \'hideSuggest\' => false in '
2189 . $table . '[\'types\'][\'' . $typeName . '\'][\'columnsOverrides\'][\'config\'][\'hideSuggest\']';
2190 }
2191 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards'][$wizardName]);
2192 }
2193 }
2194 if (empty($typeArray['columnsOverrides'][$fieldName]['config']['wizards'])) {
2195 unset($typeArray['columnsOverrides'][$fieldName]['config']['wizards']);
2196 }
2197 }
2198 }
2199 }
2200 }
2201 }
2202 }
2203 }
2204 }
2205
2206 return $tca;
2207 }
2208
2209 /**
2210 * Migrate some detail options of type=group config
2211 *
2212 * @param array $tca Given TCA
2213 * @return array Modified TCA
2214 */
2215 protected function migrateOptionsOfTypeGroup(array $tca): array
2216 {
2217 foreach ($tca as $table => &$tableDefinition) {
2218 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
2219 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
2220 if ($fieldConfig['config']['type'] === 'group') {
2221 if (isset($fieldConfig['config']['selectedListStyle'])) {
2222 unset($fieldConfig['config']['selectedListStyle']);
2223 $this->messages[] = 'The \'type\' = \'group\' option \'selectedListStyle\' is obsolete and has been dropped'
2224 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
2225 }
2226 if (isset($fieldConfig['config']['show_thumbs'])) {
2227 if ((bool)$fieldConfig['config']['show_thumbs'] === false && $fieldConfig['config']['internal_type'] === 'db') {
2228 $fieldConfig['config']['fieldWizard']['recordsOverview']['disabled'] = true;
2229 $this->messages[] = 'The \'type\' = \'group\' option \'show_thumbs\' = false is obsolete'
2230 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2231 . ' and has been migrated to'
2232 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldWizard\'][\'recordsOverview\'][\'disabled\'] = true';
2233 } elseif ((bool)$fieldConfig['config']['show_thumbs'] === false && $fieldConfig['config']['internal_type'] === 'file') {
2234 $fieldConfig['config']['fieldWizard']['fileThumbnails']['disabled'] = true;
2235 $this->messages[] = 'The \'type\' = \'group\' option \'show_thumbs\' = false is obsolete'
2236 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2237 . ' and has been migrated to'
2238 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldWizard\'][\'fileThumbnails\'][\'disabled\'] = true';
2239 } else {
2240 $this->messages[] = 'The \'type\' = \'group\' option \'show_thumbs\' is obsolete and has been dropped'
2241 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']';
2242 }
2243 unset($fieldConfig['config']['show_thumbs']);
2244 }
2245 if (isset($fieldConfig['config']['disable_controls']) && is_string($fieldConfig['config']['disable_controls'])) {
2246 $controls = GeneralUtility::trimExplode(',', $fieldConfig['config']['disable_controls'], true);
2247 foreach ($controls as $control) {
2248 if ($control === 'browser') {
2249 $fieldConfig['config']['fieldControl']['elementBrowser']['disabled'] = true;
2250 $this->messages[] = 'The \'type\' = \'group\' option \'disable_controls\' = \'browser\''
2251 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2252 . ' and has been migrated to'
2253 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldControl\'][\'elementBrowser\'][\'disabled\'] = true';
2254 } elseif ($control === 'delete') {
2255 $this->messages[] = 'The \'type\' = \'group\' option \'disable_controls\' = \'delete\''
2256 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2257 . ' and has been migrated to'
2258 . $table . '[\'columns\'][\' . $fieldName . \'][\'config\'][\'hideDeleteIcon\'] = true';
2259 $fieldConfig['config']['hideDeleteIcon'] = true;
2260 } elseif ($control === 'allowedTables') {
2261 $fieldConfig['config']['fieldWizard']['tableList']['disabled'] = true;
2262 $this->messages[] = 'The \'type\' = \'group\' option \'disable_controls\' = \'allowedTables\''
2263 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2264 . ' and has been migrated to'
2265 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldWizard\'][\'tableList\'][\'disabled\'] = true';
2266 } elseif ($control === 'upload') {
2267 $fieldConfig['config']['fieldWizard']['fileUpload']['disabled'] = true;
2268 $this->messages[] = 'The \'type\' = \'group\' option \'disable_controls\' = \'upload\''
2269 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2270 . ' and has been migrated to'
2271 . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'fieldWizard\'][\'fileUpload\'][\'disabled\'] = true';
2272 }
2273 }
2274 unset($fieldConfig['config']['disable_controls']);
2275 }
2276 }
2277 }
2278 }
2279 }
2280
2281 return $tca;
2282 }
2283
2284 /**
2285 * Migrate "showIconTable" to a field wizard, drop selicon_cols
2286 *
2287 * @param array $tca Given TCA
2288 * @return array Modified TCA
2289 */
2290 protected function migrateSelectShowIconTable(array $tca): array
2291 {
2292 foreach ($tca as $table => &$tableDefinition) {
2293 if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
2294 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
2295 if ($fieldConfig['config']['type'] === 'select'
2296 && isset($fieldConfig['config']['renderType'])
2297 && $fieldConfig['config']['renderType'] === 'selectSingle'
2298 ) {
2299 if (isset($fieldConfig['config']['showIconTable'])) {
2300 if ((bool)$fieldConfig['config']['showIconTable'] === true) {
2301 $fieldConfig['config']['fieldWizard']['selectIcons']['disabled'] = false;
2302 $this->messages[] = 'The \'type\' = \'select\' option \'showIconTable\' = true is obsolete'
2303 . ' from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']'
2304 . ' and has been migrated to'
2305 . ' [\'config\'][\'fieldWizard\'][\'selectIcons\'][\'disabled\'] = false';
2306 } else {
2307 $this->messages[] = 'The \'type\' = \'group\' option \'showIconTable\' = false is obsolete'
2308 . ' from TCA ' . $table . '[\'