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