Issue #2268939 by Gábor Hojtsy, vijaycs85: Fixed Config overrides not updated when config changes.
							parent
							
								
									074bc73e5d
								
							
						
					
					
						commit
						179c0920f5
					
				| 
						 | 
					@ -0,0 +1,113 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file
 | 
				
			||||||
 | 
					 * Contains \Drupal\Core\Config\ConfigFactoryOverrideBase.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Drupal\Core\Config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Defines a base event listener implementation configuration overrides.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					abstract class ConfigFactoryOverrideBase implements EventSubscriberInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Reacts to the ConfigEvents::COLLECTION_INFO event.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Config\ConfigCollectionInfo $collection_info
 | 
				
			||||||
 | 
					   *   The configuration collection names event.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  abstract public function addCollections(ConfigCollectionInfo $collection_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Actions to be performed to configuration override on configuration save.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Config\ConfigCrudEvent $event
 | 
				
			||||||
 | 
					   *   The config CRUD event.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  abstract public function onConfigSave(ConfigCrudEvent $event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Actions to be performed to configuration override on configuration delete.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Config\ConfigCrudEvent $event
 | 
				
			||||||
 | 
					   *   The config CRUD event.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  abstract public function onConfigDelete(ConfigCrudEvent $event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Actions to be performed to configuration override on configuration rename.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Config\ConfigRenameEvent $event
 | 
				
			||||||
 | 
					   *   The config rename event.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  abstract public function onConfigRename(ConfigRenameEvent $event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * {@inheritdoc}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static function getSubscribedEvents() {
 | 
				
			||||||
 | 
					    $events[ConfigEvents::COLLECTION_INFO][] = array('addCollections');
 | 
				
			||||||
 | 
					    $events[ConfigEvents::SAVE][] = array('onConfigSave', 20);
 | 
				
			||||||
 | 
					    $events[ConfigEvents::DELETE][] = array('onConfigDelete', 20);
 | 
				
			||||||
 | 
					    $events[ConfigEvents::RENAME][] = array('onConfigRename', 20);
 | 
				
			||||||
 | 
					    return $events;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Filters data in the override based on what is currently in configuration.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Config\Config $config
 | 
				
			||||||
 | 
					   *   Current configuration object.
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Config\StorableConfigBase $override
 | 
				
			||||||
 | 
					   *   Override object corresponding to the configuration to filter data in.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  protected function filterOverride(Config $config, StorableConfigBase $override) {
 | 
				
			||||||
 | 
					    $override_data = $override->get();
 | 
				
			||||||
 | 
					    $this->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.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  protected 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.
 | 
				
			||||||
 | 
					          $this->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]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -76,6 +76,56 @@ class ConfigLanguageOverrideTest extends DrupalUnitTestBase {
 | 
				
			||||||
    $config = \Drupal::config('config_test.new');
 | 
					    $config = \Drupal::config('config_test.new');
 | 
				
			||||||
    $this->assertIdentical($config->get('language'), NULL);
 | 
					    $this->assertIdentical($config->get('language'), NULL);
 | 
				
			||||||
    \Drupal::configFactory()->setOverrideState($old_state);
 | 
					    \Drupal::configFactory()->setOverrideState($old_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Test how overrides react to base configuration changes. Set up some base
 | 
				
			||||||
 | 
					    // values.
 | 
				
			||||||
 | 
					    \Drupal::config('config_test.foo')
 | 
				
			||||||
 | 
					      ->set('value', array('key' => 'original'))
 | 
				
			||||||
 | 
					      ->set('label', 'Original')
 | 
				
			||||||
 | 
					      ->save();
 | 
				
			||||||
 | 
					    \Drupal::languageManager()
 | 
				
			||||||
 | 
					      ->getLanguageConfigOverride('de', 'config_test.foo')
 | 
				
			||||||
 | 
					      ->set('value', array('key' => 'override'))
 | 
				
			||||||
 | 
					      ->set('label', 'Override')
 | 
				
			||||||
 | 
					      ->save();
 | 
				
			||||||
 | 
					    \Drupal::languageManager()
 | 
				
			||||||
 | 
					      ->getLanguageConfigOverride('fr', 'config_test.foo')
 | 
				
			||||||
 | 
					      ->set('value', array('key' => 'override'))
 | 
				
			||||||
 | 
					      ->save();
 | 
				
			||||||
 | 
					    \Drupal::configFactory()->clearStaticCache();
 | 
				
			||||||
 | 
					    $config = \Drupal::config('config_test.foo');
 | 
				
			||||||
 | 
					    $this->assertIdentical($config->get('value'), array('key' => 'override'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Ensure renaming the config will rename the override.
 | 
				
			||||||
 | 
					    \Drupal::configFactory()->rename('config_test.foo', 'config_test.bar');
 | 
				
			||||||
 | 
					    $config = \Drupal::config('config_test.bar');
 | 
				
			||||||
 | 
					    $this->assertEqual($config->get('value'), array('key' => 'original'));
 | 
				
			||||||
 | 
					    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.foo');
 | 
				
			||||||
 | 
					    $this->assertTrue($override->isNew());
 | 
				
			||||||
 | 
					    $this->assertEqual($override->get('value'), NULL);
 | 
				
			||||||
 | 
					    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
 | 
				
			||||||
 | 
					    $this->assertFalse($override->isNew());
 | 
				
			||||||
 | 
					    $this->assertEqual($override->get('value'), array('key' => 'override'));
 | 
				
			||||||
 | 
					    $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.bar');
 | 
				
			||||||
 | 
					    $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.bar')->clear('value.key')->save();
 | 
				
			||||||
 | 
					    $this->assertEqual($config->get('value'), array());
 | 
				
			||||||
 | 
					    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
 | 
				
			||||||
 | 
					    $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.bar');
 | 
				
			||||||
 | 
					    $this->assertTrue($override->isNew());
 | 
				
			||||||
 | 
					    $this->assertEqual($override->get('value'), NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Ensure deleting the config will delete the override.
 | 
				
			||||||
 | 
					    \Drupal::configFactory()->get('config_test.bar')->delete();
 | 
				
			||||||
 | 
					    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
 | 
				
			||||||
 | 
					    $this->assertTrue($override->isNew());
 | 
				
			||||||
 | 
					    $this->assertEqual($override->get('value'), NULL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,9 @@ namespace Drupal\language\Config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Drupal\Component\Utility\String;
 | 
					use Drupal\Component\Utility\String;
 | 
				
			||||||
use Drupal\Core\Config\ConfigCollectionInfo;
 | 
					use Drupal\Core\Config\ConfigCollectionInfo;
 | 
				
			||||||
use Drupal\Core\Config\ConfigEvents;
 | 
					use Drupal\Core\Config\ConfigCrudEvent;
 | 
				
			||||||
 | 
					use Drupal\Core\Config\ConfigFactoryOverrideBase;
 | 
				
			||||||
 | 
					use Drupal\Core\Config\ConfigRenameEvent;
 | 
				
			||||||
use Drupal\Core\Config\StorageInterface;
 | 
					use Drupal\Core\Config\StorageInterface;
 | 
				
			||||||
use Drupal\Core\Config\TypedConfigManagerInterface;
 | 
					use Drupal\Core\Config\TypedConfigManagerInterface;
 | 
				
			||||||
use Drupal\Core\Language\LanguageDefault;
 | 
					use Drupal\Core\Language\LanguageDefault;
 | 
				
			||||||
| 
						 | 
					@ -20,7 +22,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides language overrides for the configuration factory.
 | 
					 * Provides language overrides for the configuration factory.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInterface, EventSubscriberInterface {
 | 
					class LanguageConfigFactoryOverride extends ConfigFactoryOverrideBase implements LanguageConfigFactoryOverrideInterface, EventSubscriberInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * The configuration storage.
 | 
					   * The configuration storage.
 | 
				
			||||||
| 
						 | 
					@ -194,10 +196,7 @@ class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInte
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Reacts to the ConfigEvents::COLLECTION_INFO event.
 | 
					   * {@inheritdoc}
 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * @param \Drupal\Core\Config\ConfigCollectionInfo $collection_info
 | 
					 | 
				
			||||||
   *   The configuration collection names event.
 | 
					 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public function addCollections(ConfigCollectionInfo $collection_info) {
 | 
					  public function addCollections(ConfigCollectionInfo $collection_info) {
 | 
				
			||||||
    foreach (\Drupal::languageManager()->getLanguages() as $language) {
 | 
					    foreach (\Drupal::languageManager()->getLanguages() as $language) {
 | 
				
			||||||
| 
						 | 
					@ -208,9 +207,47 @@ class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInte
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * {@inheritdoc}
 | 
					   * {@inheritdoc}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static function getSubscribedEvents() {
 | 
					  public function onConfigSave(ConfigCrudEvent $event) {
 | 
				
			||||||
    $events[ConfigEvents::COLLECTION_INFO][] = array('addCollections');
 | 
					    $config = $event->getConfig();
 | 
				
			||||||
    return $events;
 | 
					    $name = $config->getName();
 | 
				
			||||||
 | 
					    foreach (\Drupal::languageManager()->getLanguages() as $language) {
 | 
				
			||||||
 | 
					      $config_translation = $this->getOverride($language->getId(), $name);
 | 
				
			||||||
 | 
					      if (!$config_translation->isNew()) {
 | 
				
			||||||
 | 
					        $this->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();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue