diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideBase.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideBase.php new file mode 100644 index 0000000..d443c05 --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideBase.php @@ -0,0 +1,113 @@ +get(); + static::filterNestedArray($config->get(), $override_data); + if (empty($override_data)) { + // If no override values are left that would apply, remove the override. + $override->delete(); + } + else { + // Otherwise set the filtered override values back. + $override->setData($override_data)->save(); + } + } + + /** + * Filters data in nested arrays. + * + * @param array $original_data + * Original data array to filter against. + * @param array $override_data + * Override data to filter. + */ + static function filterNestedArray(array $original_data, array &$override_data) { + foreach ($override_data as $key => $value) { + if (!isset($original_data[$key])) { + // The original data is not there anymore, remove the override. + unset($override_data[$key]); + } + elseif (is_array($override_data[$key])) { + if (is_array($original_data[$key])) { + // Do the filtering one level deeper. + static::filterNestedArray($original_data[$key], $override_data[$key]); + // If no overrides are left under this level, remove the level. + if (empty($override_data[$key])) { + unset($override_data[$key]); + } + } + else { + // The override is an array but the value is not, this will not go + // well, remove the override. + unset($override_data[$key]); + } + } + } + } + +} diff --git a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php index e0d5b6b..308b524 100644 --- a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php +++ b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php @@ -82,6 +82,55 @@ function testConfigLanguageOverride() { $config = \Drupal::config('config_test.new'); $this->assertIdentical($config->get('language'), NULL); \Drupal::configFactory()->setOverrideState($old_state); + + // Test how overrides react to base configuration changes. Set up some base + // values. + \Drupal::languageManager() + ->getLanguageConfigOverride('de', 'config_test.overide') + ->set('value', array('key' => 'override')) + ->set('label', 'Override') + ->save(); + \Drupal::languageManager() + ->getLanguageConfigOverride('fr', 'config_test.overide') + ->set('value', array('key' => 'override')) + ->save(); + \Drupal::config('config_test.overide') + ->set('value', array('key' => 'original')) + ->set('label', 'Original') + ->save(); + $config = \Drupal::config('config_test.overide'); + $this->assertIdentical($config->get('value'), array('key' => 'override')); + + // Ensure renaming the config will rename the override. + \Drupal::configFactory()->rename('config_test.overide', 'config_test.override'); + $config = \Drupal::config('config_test.override'); + $this->assertEqual($config->get('value'), array('key' => 'original')); + $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.overide'); + $this->assertTrue($override->isNew()); + $this->assertEqual($override->get('value'), NULL); + $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.override'); + $this->assertFalse($override->isNew()); + $this->assertEqual($override->get('value'), array('key' => 'override')); + $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.override'); + $this->assertFalse($override->isNew()); + $this->assertEqual($override->get('value'), array('key' => 'override')); + + // Ensure changing data in the config will update the overrides. + $config = \Drupal::config('config_test.override')->clear('value.key')->save(); + $this->assertEqual($config->get('value'), array()); + $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.override'); + $this->assertFalse($override->isNew()); + $this->assertEqual($override->get('value'), NULL); + // The French override will become empty and therefore removed. + $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.override'); + $this->assertTrue($override->isNew()); + $this->assertEqual($override->get('value'), NULL); + + // Ensure deleting the config will delete the override. + \Drupal::configFactory()->get('config_test.override')->delete(); + $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.override'); + $this->assertTrue($override->isNew()); + $this->assertEqual($override->get('value'), NULL); } } diff --git a/core/modules/language/src/Config/LanguageConfigFactoryOverride.php b/core/modules/language/src/Config/LanguageConfigFactoryOverride.php index 6c71478..b681618 100644 --- a/core/modules/language/src/Config/LanguageConfigFactoryOverride.php +++ b/core/modules/language/src/Config/LanguageConfigFactoryOverride.php @@ -9,7 +9,10 @@ use Drupal\Component\Utility\String; use Drupal\Core\Config\ConfigCollectionInfo; +use Drupal\Core\Config\ConfigCrudEvent; use Drupal\Core\Config\ConfigEvents; +use Drupal\Core\Config\ConfigFactoryOverrideBase; +use Drupal\Core\Config\ConfigRenameEvent; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Language\LanguageDefault; @@ -20,7 +23,7 @@ /** * Provides language overrides for the configuration factory. */ -class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInterface, EventSubscriberInterface { +class LanguageConfigFactoryOverride extends ConfigFactoryOverrideBase implements LanguageConfigFactoryOverrideInterface, EventSubscriberInterface { /** * The configuration storage. @@ -194,10 +197,7 @@ protected function getLangcodeFromCollectionName($collection) { } /** - * Reacts to the ConfigEvents::COLLECTION_INFO event. - * - * @param \Drupal\Core\Config\ConfigCollectionInfo $collection_info - * The configuration collection names event. + * {@inheritdoc} */ public function addCollections(ConfigCollectionInfo $collection_info) { foreach (\Drupal::languageManager()->getLanguages() as $language) { @@ -208,9 +208,47 @@ public function addCollections(ConfigCollectionInfo $collection_info) { /** * {@inheritdoc} */ - static function getSubscribedEvents() { - $events[ConfigEvents::COLLECTION_INFO][] = array('addCollections'); - return $events; + public function onConfigSave(ConfigCrudEvent $event) { + $config = $event->getConfig(); + $name = $config->getName(); + foreach (\Drupal::languageManager()->getLanguages() as $language) { + $config_translation = $this->getOverride($language->getId(), $name); + if (!$config_translation->isNew()) { + static::filterOverride($config, $config_translation); + } + } + } + + /** + * {@inheritdoc} + */ + public function onConfigRename(ConfigRenameEvent $event) { + $config = $event->getConfig(); + $name = $config->getName(); + $old_name = $event->getOldName(); + foreach (\Drupal::languageManager()->getLanguages() as $language) { + $config_translation = $this->getOverride($language->getId(), $old_name); + if (!$config_translation->isNew()) { + $saved_config = $config_translation->get(); + $storage = $this->getStorage($language->getId()); + $storage->write($name, $saved_config); + $config_translation->delete(); + } + } + } + + /** + * {@inheritdoc} + */ + public function onConfigDelete(ConfigCrudEvent $event) { + $config = $event->getConfig(); + $name = $config->getName(); + foreach (\Drupal::languageManager()->getLanguages() as $language) { + $config_translation = $this->getOverride($language->getId(), $name); + if (!$config_translation->isNew()) { + $config_translation->delete(); + } + } } }