From b6c72882bf60a3c8243bd58836cd052f0dbc794f Mon Sep 17 00:00:00 2001
From: Malte Koitka <malte@cytrus.de>
Date: Wed, 3 May 2017 09:42:16 +0200
Subject: [PATCH] [BUGFIX] TcaMigration should not skip on existing
 overrideChildTca

If an overideChildTca key is already added by a TYPO3 core
function like ExtensionManagementUtility::getFileFieldTCAConfig()
the TCA migration should not be skipped. Otherwise the config will
be incomplete and result in missing fields.

The migration is changed that old "foreign_types",
"foreign_selector_fieldTcaOverride" and "foreign_record_defaults"
are merged into new "overrideChildTca", but the new settings
are keps (take precedence) if given.

Resolves: #80719
Resolves: #81045
Releases: master, 8.7
Change-Id: Ic8a0338e0a9882b3b1e7abcd3123fbd7aa2b3505
Reviewed-on: https://review.typo3.org/52693
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Reviewed-by: Henning Liebe <h.liebe@neusta.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../core/Classes/Migrations/TcaMigration.php  | 36 +++++++---
 .../Unit/Migrations/TcaMigrationTest.php      | 71 +++++++++++++++++--
 2 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/typo3/sysext/core/Classes/Migrations/TcaMigration.php b/typo3/sysext/core/Classes/Migrations/TcaMigration.php
index 5699e8834eb6..f54f61bcbdab 100644
--- a/typo3/sysext/core/Classes/Migrations/TcaMigration.php
+++ b/typo3/sysext/core/Classes/Migrations/TcaMigration.php
@@ -2448,12 +2448,12 @@ class TcaMigration
                             $this->messages[] = 'The \'foreign_types\' property from TCA ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnOverrides\'][\'' . $fieldName . '\'][\'config\']  and has been migrated to ' . $table . '[\'types\'][\'' . $typeName . '\'][\'columnOverrides\'][\'' . $fieldName . '\'][\'config\'][\'overrideChildTca\'][\'types\']';
                         }
                         if (isset($fieldConfig['config']['foreign_selector_fieldTcaOverride']) && is_array($fieldConfig['config']['foreign_selector_fieldTcaOverride'])) {
+                            $foreignSelectorFieldName = '';
                             if (isset($fieldConfig['config']['foreign_selector']) && is_string($fieldConfig['config']['foreign_selector'])) {
                                 $foreignSelectorFieldName = $fieldConfig['config']['foreign_selector'];
                             } elseif (isset($tca[$table]['columns'][$fieldName]['config']['foreign_selector']) && is_string($tca[$table]['columns'][$fieldName]['config']['foreign_selector'])) {
                                 $foreignSelectorFieldName = $tca[$table]['columns'][$fieldName]['config']['foreign_selector'];
                             }
-
                             if ($foreignSelectorFieldName) {
                                 $fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName] = $fieldConfig['config']['foreign_selector_fieldTcaOverride'];
                                 unset($fieldConfig['config']['foreign_selector_fieldTcaOverride']);
@@ -2474,28 +2474,44 @@ class TcaMigration
             }
             if (isset($tableDefinition['columns']) && is_array($tableDefinition['columns'])) {
                 foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
-                    if (isset($fieldConfig['config']['overrideChildTca'])
-                        || $fieldConfig['config']['type'] !== 'inline'
-                    ) {
-                        // The new config is either set intentionally for compatibility
-                        // or accidentally. In any case we keep the new config and skip the migration.
+                    if ($fieldConfig['config']['type'] !== 'inline') {
                         continue;
                     }
                     if (isset($fieldConfig['config']['foreign_types']) && is_array($fieldConfig['config']['foreign_types'])) {
-                        $fieldConfig['config']['overrideChildTca']['types'] = $fieldConfig['config']['foreign_types'];
+                        if (isset($fieldConfig['config']['overrideChildTca']['types'])
+                            && is_array($fieldConfig['config']['overrideChildTca']['types'])
+                        ) {
+                            $fieldConfig['config']['overrideChildTca']['types'] = array_replace_recursive(
+                                $fieldConfig['config']['foreign_types'],
+                                $fieldConfig['config']['overrideChildTca']['types']
+                            );
+                        } else {
+                            $fieldConfig['config']['overrideChildTca']['types'] = $fieldConfig['config']['foreign_types'];
+                        }
                         unset($fieldConfig['config']['foreign_types']);
                         $this->messages[] = 'The \'foreign_types\' property from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']  and has been migrated to ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'overrideChildTca\'][\'types\']';
                     }
                     if (isset($fieldConfig['config']['foreign_selector'], $fieldConfig['config']['foreign_selector_fieldTcaOverride']) && is_string($fieldConfig['config']['foreign_selector']) && is_array($fieldConfig['config']['foreign_selector_fieldTcaOverride'])) {
                         $foreignSelectorFieldName = $fieldConfig['config']['foreign_selector'];
-                        $fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName] = $fieldConfig['config']['foreign_selector_fieldTcaOverride'];
+                        if (isset($fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName])
+                            && is_array($fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName])
+                        ) {
+                            $fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName] = array_replace_recursive(
+                                $fieldConfig['config']['foreign_selector_fieldTcaOverride'],
+                                $fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName]
+                            );
+                        } else {
+                            $fieldConfig['config']['overrideChildTca']['columns'][$foreignSelectorFieldName] = $fieldConfig['config']['foreign_selector_fieldTcaOverride'];
+                        }
                         unset($fieldConfig['config']['foreign_selector_fieldTcaOverride']);
                         $this->messages[] = 'The \'foreign_selector_fieldTcaOverride\' property from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\']  and has been migrated to ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'overrideChildTca\'][\'columns\'][\'' . $foreignSelectorFieldName . '\']';
                     }
                     if (isset($fieldConfig['config']['foreign_record_defaults']) && is_array($fieldConfig['config']['foreign_record_defaults'])) {
                         foreach ($fieldConfig['config']['foreign_record_defaults'] as $childFieldName => $defaultValue) {
-                            $fieldConfig['config']['overrideChildTca']['columns'][$childFieldName]['config']['default'] = $defaultValue;
-                            $this->messages[] = 'The \'foreign_record_defaults\' property from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'' . $childFieldName . '\']  and has been migrated to ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'overrideChildTca\'][\'columns\'][\'' . $childFieldName . '\'][\'config\'][\'default\']';
+                            if (!isset($fieldConfig['config']['overrideChildTca']['columns'][$childFieldName]['config']['default'])) {
+                                $fieldConfig['config']['overrideChildTca']['columns'][$childFieldName]['config']['default'] = $defaultValue;
+                                $this->messages[] = 'The \'foreign_record_defaults\' property from TCA ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'' . $childFieldName . '\']  and has been migrated to ' . $table . '[\'columns\'][\'' . $fieldName . '\'][\'config\'][\'overrideChildTca\'][\'columns\'][\'' . $childFieldName . '\'][\'config\'][\'default\']';
+                            }
                         }
                         unset($fieldConfig['config']['foreign_record_defaults']);
                     }
diff --git a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php
index 936caf1c63d0..0b989724529a 100644
--- a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php
+++ b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php
@@ -6158,7 +6158,7 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
     /**
      * @test
      */
-    public function migrateOfChildOverrideIsSkippedWhenNewConfigIsFound()
+    public function migrateForeignTypesMergedIntoExistingOverrideChildTca()
     {
         $input = [
             'aTable' => [
@@ -6168,7 +6168,13 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                             'type' => 'inline',
                             'foreign_types' => [
                                 '0' => [
-                                    'showitem' => 'bar'
+                                    // This does NOT override existing 'showitem'='baz' below
+                                    'showitem' => 'doesNotOverrideExistingSetting',
+                                    // This is added to existing types 0 below
+                                    'bitmask_value_field' => 42,
+                                ],
+                                'otherType' => [
+                                    'showitem' => 'aField',
                                 ],
                             ],
                             'overrideChildTca' => [
@@ -6183,7 +6189,28 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                 ],
             ],
         ];
-        $expected = $input;
+        $expected = [
+            'aTable' => [
+                'columns' => [
+                    'foo' => [
+                        'config' => [
+                            'type' => 'inline',
+                            'overrideChildTca' => [
+                                'types' => [
+                                    '0' => [
+                                        'showitem' => 'baz',
+                                        'bitmask_value_field' => 42,
+                                    ],
+                                    'otherType' => [
+                                        'showitem' => 'aField',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
         $subject = new TcaMigration();
         $this->assertEquals($expected, $subject->migrate($input));
     }
@@ -6200,8 +6227,22 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                         'config' => [
                             'type' => 'inline',
                             'foreign_record_defaults' => [
-                                'aField' => 'overriddenValue',
-                                'bField' => 'overriddenValue',
+                                'aField' => 'doesNotOverrideExistingOverrideChildTcaDefault',
+                                'bField' => 'aDefault',
+                            ],
+                            'overrideChildTca' => [
+                                'columns' => [
+                                    'aField' => [
+                                        'config' => [
+                                            'default' => 'aDefault'
+                                        ],
+                                    ],
+                                    'cField' => [
+                                        'config' => [
+                                            'default' => 'aDefault'
+                                        ],
+                                    ],
+                                ],
                             ],
                         ],
                     ],
@@ -6218,12 +6259,17 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                                 'columns' => [
                                     'aField' => [
                                         'config' => [
-                                            'default' => 'overriddenValue'
+                                            'default' => 'aDefault'
                                         ],
                                     ],
                                     'bField' => [
                                         'config' => [
-                                            'default' => 'overriddenValue'
+                                            'default' => 'aDefault'
+                                        ],
+                                    ],
+                                    'cField' => [
+                                        'config' => [
+                                            'default' => 'aDefault'
                                         ],
                                     ],
                                 ],
@@ -6254,12 +6300,22 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                                 'config' => [
                                     'aGivenSetting' => 'overrideValue',
                                     'aNewSetting' => 'anotherNewValue',
+                                    'anExistingSettingInOverrideChildTca' => 'doesNotOverrideExistingOverrideChildTcaDefault',
                                     'appearance' => [
                                         'elementBrowserType' => 'file',
                                         'elementBrowserAllowed' => 'jpg,png'
                                     ],
                                 ],
                             ],
+                            'overrideChildTca' => [
+                                'columns' => [
+                                    'uid_local' => [
+                                        'config' => [
+                                            'anExistingSettingInOverrideChildTca' => 'notOverridenByOldSetting',
+                                        ],
+                                    ],
+                                ],
+                            ],
                         ],
                     ],
                 ],
@@ -6277,6 +6333,7 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                                     'uid_local' => [
                                         'label' => 'aDifferentLabel',
                                         'config' => [
+                                            'anExistingSettingInOverrideChildTca' => 'notOverridenByOldSetting',
                                             'aGivenSetting' => 'overrideValue',
                                             'aNewSetting' => 'anotherNewValue',
                                             'appearance' => [
-- 
GitLab