d51b42ccc8e1afef638d085e61dd98d95df2dee7
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Migrations / TcaMigration.php
1 <?php
2 namespace TYPO3\CMS\Core\Migrations;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * Migrate TCA from old to new syntax. Used in bootstrap and Flex Form Data Structures.
21 *
22 * @internal Class and API may change any time.
23 */
24 class TcaMigration {
25
26 /**
27 * Accumulate migration messages
28 *
29 * @var array
30 */
31 protected $messages = array();
32
33 /**
34 * Migrate old TCA to new TCA.
35 *
36 * See unit tests for details.
37 *
38 * @param array $tca
39 * @return array
40 */
41 public function migrate(array $tca) {
42 $tca = $this->migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig($tca);
43 $tca = $this->migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig($tca);
44 $tca = $this->migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides($tca);
45 // @todo: if showitem/defaultExtras wizards[xy] is migrated to columnsOverrides here, enableByTypeConfig could be dropped
46 return $tca;
47 }
48
49 /**
50 * Get messages of migrated fields. Can be used for deprecation messages after migrate() was called.
51 *
52 * @return array Migration messages
53 */
54 public function getMessages() {
55 return $this->messages;
56 }
57
58 /**
59 * Migrate type=text field with t3editor wizard to renderType=t3editor without this wizard
60 *
61 * @param array $tca Incoming TCA
62 * @return array Migrated TCA
63 */
64 protected function migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig(array $tca) {
65 $newTca = $tca;
66 foreach ($tca as $table => $tableDefinition) {
67 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
68 continue;
69 }
70 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
71 if (
72 !empty($fieldConfig['config']['type']) // type is set
73 && trim($fieldConfig['config']['type']) === 'text' // to "text"
74 && isset($fieldConfig['config']['wizards'])
75 && is_array($fieldConfig['config']['wizards']) // and there are wizards
76 ) {
77 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
78 if (
79 !empty($wizardConfig['userFunc']) // a userFunc is defined
80 && trim($wizardConfig['userFunc']) === 'TYPO3\\CMS\\T3editor\\FormWizard->main' // and set to FormWizard
81 && (
82 !isset($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is not set
83 || (isset($wizardConfig['enableByTypeConfig']) && !$wizardConfig['enableByTypeConfig']) // or set, but not enabled
84 )
85 ) {
86 // Set renderType from text to t3editor
87 $newTca[$table]['columns'][$fieldName]['config']['renderType'] = 't3editor';
88 // Unset this wizard definition
89 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
90 // Move format parameter
91 if (!empty($wizardConfig['params']['format'])) {
92 $newTca[$table]['columns'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
93 }
94 $this->messages[] = 'Migrated t3editor wizard in TCA of table ' . $table . ' field ' . $fieldName . ' to a renderType definition.';
95 }
96 }
97 // If no wizard is left after migration, unset the whole sub array
98 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
99 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
100 }
101 }
102 }
103 }
104 return $newTca;
105 }
106
107 /**
108 * Remove "style pointer", the 5th parameter from "types" "showitem" configuration.
109 * Move "specConf", 4th parameter from "tyes" "showitem" to "types" "columnsOverrides.
110 *
111 * @param array $tca Incoming TCA
112 * @return array Modified TCA
113 */
114 protected function migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig(array $tca) {
115 $newTca = $tca;
116 foreach ($tca as $table => $tableDefinition) {
117 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
118 continue;
119 }
120 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
121 if (!is_string($typeArray['showitem']) || strpos($typeArray['showitem'], ';') === FALSE) {
122 // Continue directly if no semicolon is found
123 continue;
124 }
125 $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], TRUE);
126 $newFieldStrings = array();
127 foreach ($itemList as $fieldString) {
128 $fieldString = rtrim($fieldString, ';');
129 // Unpack the field definition, migrate and remove as much as possible
130 // Keep empty parameters in trimExplode here (third parameter FALSE), so position is not changed
131 $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
132 $fieldArray = array(
133 'fieldName' => isset($fieldArray[0]) ? $fieldArray[0] : '',
134 'fieldLabel' => isset($fieldArray[1]) ? $fieldArray[1] : NULL,
135 'paletteName' => isset($fieldArray[2]) ? $fieldArray[2] : NULL,
136 'fieldExtra' => isset($fieldArray[3]) ? $fieldArray[3] : NULL,
137 );
138 $fieldName = $fieldArray['fieldName'];
139 if (!empty($fieldArray['fieldExtra'])) {
140 // Move fieldExtra "specConf" to columnsOverrides "defaultExtras"
141 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'])) {
142 $newTca[$table]['types'][$typeName]['columnsOverrides'] = array();
143 }
144 if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']])) {
145 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']] = array();
146 }
147 // Merge with given defaultExtras from columns.
148 // They will be the first part of the string, so if "specConf" from types changes the same settings,
149 // those will override settings from defaultExtras of columns
150 $newDefaultExtras = array();
151 if (!empty($tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'])) {
152 $newDefaultExtras[] = $tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'];
153 }
154 $newDefaultExtras[] = $fieldArray['fieldExtra'];
155 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']]['defaultExtras'] = implode(':', $newDefaultExtras);
156 }
157 unset($fieldArray['fieldExtra']);
158 if (count($fieldArray) === 3 && empty($fieldArray['paletteName'])) {
159 unset($fieldArray['paletteName']);
160 }
161 if (count($fieldArray) === 2 && empty($fieldArray['fieldLabel'])) {
162 unset($fieldArray['fieldLabel']);
163 }
164 if (count($fieldArray) === 1 && empty($fieldArray['fieldName'])) {
165 // The field may vanish if nothing is left
166 unset($fieldArray['fieldName']);
167 }
168 $newFieldString = implode(';', $fieldArray);
169 if ($newFieldString !== $fieldString) {
170 $this->messages[] = 'Changed showitem string of TCA table "' . $table . '" type "' . $typeName . '" due to changed field "' . $fieldName . '".';
171 }
172 if (!empty($newFieldString)) {
173 $newFieldStrings[] = $newFieldString;
174 }
175 }
176 $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
177 }
178 }
179 return $newTca;
180 }
181
182 /**
183 * Migrate type=text field with t3editor wizard that is "enableByTypeConfig" to columnsOverrides
184 * with renderType=t3editor
185 *
186 * @param array $tca Incoming TCA
187 * @return array Migrated TCA
188 */
189 protected function migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides(array $tca) {
190 $newTca = $tca;
191 foreach ($tca as $table => $tableDefinition) {
192 if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
193 continue;
194 }
195 foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
196 if (
197 !empty($fieldConfig['config']['type']) // type is set
198 && trim($fieldConfig['config']['type']) === 'text' // to "text"
199 && isset($fieldConfig['config']['wizards'])
200 && is_array($fieldConfig['config']['wizards']) // and there are wizards
201 ) {
202 foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
203 if (
204 !empty($wizardConfig['userFunc']) // a userFunc is defined
205 && trim($wizardConfig['userFunc']) === 'TYPO3\CMS\T3editor\FormWizard->main' // and set to FormWizard
206 && !empty($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is enabled
207 ) {
208 // Remove this wizard
209 unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
210 // Find configured types that use this wizard
211 if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
212 // No type definition at all ... continue directly
213 continue;
214 }
215 foreach ($tableDefinition['types'] as $typeName => $typeArray) {
216 if (
217 empty($typeArray['columnsOverrides'][$fieldName]['defaultExtras'])
218 || strpos($typeArray['columnsOverrides'][$fieldName]['defaultExtras'], $wizardName) === FALSE
219 ) {
220 // Continue directly if this wizard is not enabled for given type
221 continue;
222 }
223 $defaultExtras = $typeArray['columnsOverrides'][$fieldName]['defaultExtras'];
224 $defaultExtrasArray = GeneralUtility::trimExplode(':', $defaultExtras, TRUE);
225 $newDefaultExtrasArray = array();
226 foreach ($defaultExtrasArray as $fieldExtraField) {
227 // There might be multiple enabled wizards separated by | ... split them
228 if (substr($fieldExtraField, 0, 8) === 'wizards[') {
229 $enabledWizards = substr($fieldExtraField, 8, strlen($fieldExtraField) - 8); // Cut off "wizards[
230 $enabledWizards = substr($enabledWizards, 0, strlen($enabledWizards) - 1);
231 $enabledWizardsArray = GeneralUtility::trimExplode('|', $enabledWizards, TRUE);
232 $newEnabledWizardsArray = array();
233 foreach ($enabledWizardsArray as $enabledWizardName) {
234 if ($enabledWizardName === $wizardName) {
235 // Found a columnsOverrides configuration that has this wizard enabled
236 // Force renderType = t3editor
237 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['renderType'] = 't3editor';
238 // Transfer format option if given
239 if (!empty($wizardConfig['params']['format'])) {
240 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
241 }
242 $this->messages[] = 'Migrated t3editor wizard in TCA of table ' . $table . ' field ' . $fieldName
243 . ' to a renderType definition with columnsOverrides in type ' . $typeName . '.';
244 } else {
245 // Some other enabled wizard
246 $newEnabledWizardsArray[] = $enabledWizardName;
247 }
248 }
249 if (!empty($newEnabledWizardsArray)) {
250 $newDefaultExtrasArray[] = 'wizards[' . implode('|', $newEnabledWizardsArray) . ']';
251 }
252 } else {
253 $newDefaultExtrasArray[] = $fieldExtraField;
254 }
255 }
256 if (!empty($newDefaultExtrasArray)) {
257 $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras'] = implode(':', $newDefaultExtrasArray);
258 } else {
259 unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras']);
260 }
261 }
262 }
263 }
264 // If no wizard is left after migration, unset the whole sub array
265 if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
266 unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
267 }
268 }
269 }
270 }
271 return $newTca;
272 }
273
274 }