diff --git a/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php b/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php index 9e150da61e1e3dc3ced21895e3e7e098aa510484..53f563c47058e6d7513b393ecacfd14a855f2907 100644 --- a/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php +++ b/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php @@ -390,12 +390,9 @@ class SiteConfigurationController } } - // keep root config objects not given via GUI - // this way extension authors are able to use their own objects on root level - // that are not configurable via GUI - // however: we overwrite the full subset of any GUI object to make sure we have a clean state - $newSysSiteData = array_merge($currentSiteConfiguration, $newSysSiteData); - $newSiteConfiguration = $this->validateFullStructure($newSysSiteData); + $newSiteConfiguration = $this->validateFullStructure( + $this->getMergeSiteData($currentSiteConfiguration, $newSysSiteData) + ); // Persist the configuration $siteConfigurationManager = GeneralUtility::makeInstance(SiteConfiguration::class); @@ -808,6 +805,35 @@ class SiteConfigurationController return !empty($value) || $value === '0'; } + /** + * Method keeps root config objects, which are not given via GUI. This way, + * extension authors are able to use their own objects on root level that are + * not configurable via GUI. However: We overwrite the full subset of any GUI + * object to make sure we have a clean state. + * + * Additionally, we also keep the baseVariants of languages, since they + * can't be modified via the GUI, but are part of the public API. + */ + protected function getMergeSiteData(array $currentSiteConfiguration, array $newSysSiteData): array + { + $newSysSiteData = array_merge($currentSiteConfiguration, $newSysSiteData); + + // @todo: this should go away, once base variants for languages are managable via the GUI. + $existingLanguageConfigurationsWithBaseVariants = []; + foreach ($currentSiteConfiguration['languages'] ?? [] as $languageConfiguration) { + if (isset($languageConfiguration['baseVariants'])) { + $existingLanguageConfigurationsWithBaseVariants[$languageConfiguration['languageId']] = $languageConfiguration['baseVariants']; + } + } + foreach ($newSysSiteData['languages'] ?? [] as $key => $languageConfiguration) { + if (isset($existingLanguageConfigurationsWithBaseVariants[$languageConfiguration['languageId']])) { + $newSysSiteData['languages'][$key]['baseVariants'] = $existingLanguageConfigurationsWithBaseVariants[$languageConfiguration['languageId']]; + } + } + + return $newSysSiteData; + } + protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; diff --git a/typo3/sysext/backend/Tests/Unit/Controller/SiteConfigurationControllerTest.php b/typo3/sysext/backend/Tests/Unit/Controller/SiteConfigurationControllerTest.php index a653f9dfd4e8b2f4d0a258976d5ee4d8bda4ecbf..25792f1eafb12e99f232e72c49d40dcb50d047d4 100644 --- a/typo3/sysext/backend/Tests/Unit/Controller/SiteConfigurationControllerTest.php +++ b/typo3/sysext/backend/Tests/Unit/Controller/SiteConfigurationControllerTest.php @@ -126,4 +126,57 @@ class SiteConfigurationControllerTest extends UnitTestCase self::assertEquals($expected, $mockedSiteConfigurationController->_call('getDuplicatedEntryPoints', $sites, $rootPages)); } + + /** + * @test + */ + public function languageBaseVariantsAreKept(): void + { + $mockedSiteConfigurationController = $this->getAccessibleMock(SiteConfigurationController::class, ['dummy'], [], '', false); + + $currentSiteConfig = [ + 'base' => '//domain1.tld/', + 'websiteTitle' => 'domain1', + 'languages' => [ + 0 => [ + 'languageId' => 0, + 'title' => 'English', + 'base' => '/', + 'baseVariants' => [ + [ + 'base' => '/en', + ], + ], + ], + ], + ]; + + $newSiteConfig = $currentSiteConfig; + $newSiteConfig['rootPageId'] = 123; + $newSiteConfig['websiteTitle'] = 'domain1 renamed'; + unset($newSiteConfig['languages'][0]['baseVariants']); + + $expected = [ + 'base' => '//domain1.tld/', + 'rootPageId' => 123, + 'websiteTitle' => 'domain1 renamed', + 'languages' => [ + 0 => [ + 'languageId' => 0, + 'title' => 'English', + 'base' => '/', + 'baseVariants' => [ + [ + 'base' => '/en', + ], + ], + ], + ], + ]; + + self::assertEquals( + $expected, + $mockedSiteConfigurationController->_call('getMergeSiteData', $currentSiteConfig, $newSiteConfig) + ); + } }