diff -u b/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php --- b/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -21,7 +21,7 @@ * Each configuration object gets a storage controller object injected, which * is used for reading and writing the configuration data. * - * @see Drupal\Core\Config\StorageInterface + * @see \Drupal\Core\Config\StorageInterface */ class ConfigFactory { @@ -82,9 +82,9 @@ * @param \Drupal\Core\Config\TypedConfigManager $typed_config * The typed configuration manager. * @param \Drupal\Core\Language\Language - * (optional) The language for this configuration. If a language is set then - * the config factory will use it to override configuration data is - * overrides are available. + * (optional) The language for this configuration. The config factory will + * use it to override configuration data if language overrides are + * available. */ public function __construct(StorageInterface $storage, EventDispatcher $event_dispatcher, TypedConfigManager $typed_config, Language $language = NULL) { $this->storage = $storage; @@ -119,14 +119,37 @@ * A configuration object. */ public function get($name) { - $names = array($name); - if ($config = $this->loadMultiple($names)) { + global $conf; + + if ($config = $this->loadMultiple(array($name))) { return $config[$name]; } else { + // If the configuration object does not exist in the configuration storage + // create a new object and add it to the static cache. $cache_key = $this->getCacheKey($name); - if (!isset($this->cache[$cache_key])) { - $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language); + $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language); + + if ($this->canOverride($name)) { + // Get and apply any language overrides. + if ($this->language) { + $language_overrides = $this->storage->read($this->getLanguageConfigName($this->language->id, $name)); + } + else { + $language_overrides = FALSE; + } + if (is_array($language_overrides)) { + $this->cache[$cache_key]->setLanguageOverride($language_overrides); + } + // Get and apply any module overrides. + $module_overrides = $this->loadModuleOverrides(array($name)); + if (isset($module_overrides[$name])) { + $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]); + } + // Apply any settigns.php overrides. + if (isset($conf[$name])) { + $this->cache[$cache_key]->setSettingsOverride($conf[$name]); + } } return $this->cache[$cache_key]; } @@ -151,7 +174,7 @@ foreach ($names as $key => $name) { // @todo: Deleted configuration stays in $this->cache, only return - // config entities that are not new. + // configuration objects that are not new. $cache_key = $this->getCacheKey($name); if (isset($this->cache[$cache_key]) && !$this->cache[$cache_key]->isNew()) { $list[$name] = $this->cache[$cache_key]; @@ -161,36 +184,42 @@ // Pre-load remaining configuration files. if (!empty($names)) { + // Initialise override information. + $module_overrides = array(); + $language_names = array(); + if ($this->useOverrides) { - $moduleOverrides = $this->loadModuleOverrides($names); // In order to make just one call to storage, add in language names. // Keep track of them separately, so we can get language override data // returned from storage and set it on new Config objects. $language_names = $this->getLanguageConfigNames($names); - $storage_data = $this->storage->readMultiple(array_merge($names, array_values($language_names))); } - else { - $moduleOverrides = array(); - $language_names = array(); - $storage_data = $this->storage->readMultiple($names); + + $storage_data = $this->storage->readMultiple(array_merge($names, array_values($language_names))); + + if ($this->useOverrides && !empty($storage_data)) { + // Only fire module override event if we have configuration to override. + $module_overrides = $this->loadModuleOverrides($names); } foreach ($storage_data as $name => $data) { if (in_array($name, $language_names)) { - // Language override configuration is not regular configuration and - // therefore not cached or overridden. + // Language override configuration is used to override other + // configuration. Therefore, when it has been added to the + // $storage_data it is not statically cached in the config factory or + // overridden in any way. continue; } $cache_key = $this->getCacheKey($name); $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language); $this->cache[$cache_key]->initWithData($data); - if ($this->useOverrides) { + if ($this->canOverride($name)) { if (isset($language_names[$name]) && isset($storage_data[$language_names[$name]])) { $this->cache[$cache_key]->setLanguageOverride($storage_data[$language_names[$name]]); } - if (isset($moduleOverrides[$name])) { - $this->cache[$cache_key]->setModuleOverride($moduleOverrides[$name]); + if (isset($module_overrides[$name])) { + $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]); } if (isset($conf[$name])) { $this->cache[$cache_key]->setSettingsOverride($conf[$name]); @@ -387,2 +416,17 @@ -} + /** + * Determines if a particular configuration object can be overridden. + * + * Language override configuration should not be overridden. + * + * @param string $name + * The name of the configuration object. + * + * @return bool + * TRUE if the configuration object can be overridden. + */ + protected function canOverride($name) { + return $this->useOverrides && !(strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0); + } + +} diff -u b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php --- b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php @@ -60,6 +60,25 @@ \Drupal::configFactory()->setLanguage(language_load('de')); $config = \Drupal::config('config_test.system'); $this->assertIdentical($config->get('foo'), 'de bar'); + + // Test overrides of completely new configuration objects. In normal runtime + // this should only happen for configuration entities as we should not be + // creating simple configuration objects on the fly. + $language_config_name = \Drupal::configFactory()->getLanguageConfigName('de', 'config_test.new'); + \Drupal::config($language_config_name)->set('language', 'override')->save(); + \Drupal::config('config_test.new'); + $config = \Drupal::config('config_test.new'); + $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new'); + $this->assertIdentical($config->get('language'), 'override'); + \Drupal::configFactory()->disableOverrides(); + $config = \Drupal::config('config_test.new'); + $this->assertIdentical($config->get('language'), NULL); + \Drupal::configFactory()->enableOverrides(); + + // Ensure that language configuration overrides can not be overridden. + global $conf; + $conf[$language_config_name]['language'] = 'conf cannot override'; + $this->assertIdentical(\Drupal::config($language_config_name)->get('language'), 'override'); } } diff -u b/core/modules/config/lib/Drupal/config/Tests/ConfigModuleOverridesTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigModuleOverridesTest.php --- b/core/modules/config/lib/Drupal/config/Tests/ConfigModuleOverridesTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigModuleOverridesTest.php @@ -46,6 +46,17 @@ $this->assertEqual($overridden_name, $config_factory->get('system.site')->get('name')); $this->assertEqual($overridden_slogan, $config_factory->get('system.site')->get('slogan')); + // Test overrides of completely new configuration objects. In normal runtime + // this should only happen for configuration entities as we should not be + // creating simple configuration objects on the fly. + $config = \Drupal::config('config_override.new'); + $this->assertTrue($config->isNew(), 'The configuration object config_override.new is new'); + $this->assertIdentical($config->get('module'), 'override'); + \Drupal::configFactory()->disableOverrides(); + $config = \Drupal::config('config_override.new'); + $this->assertIdentical($config->get('module'), NULL); + \Drupal::configFactory()->enableOverrides(); + unset($GLOBALS['config_test_run_module_overrides']); } } diff -u b/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php --- b/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php @@ -115,6 +115,18 @@ $this->assertIdentical($config->get('foo'), $conf['config_test.system']['foo']); $this->assertIdentical($config->get('baz'), $conf['config_test.system']['baz']); $this->assertIdentical($config->get('404'), $conf['config_test.system']['404']); + + // Test overrides of completely new configuration objects. In normal runtime + // this should only happen for configuration entities as we should not be + // creating simple configuration objects on the fly. + $conf['config_test.new']['key'] = 'override'; + $config = \Drupal::config('config_test.new'); + $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new'); + $this->assertIdentical($config->get('key'), 'override'); + \Drupal::configFactory()->disableOverrides(); + $config = \Drupal::config('config_test.new'); + $this->assertIdentical($config->get('key'), NULL); + \Drupal::configFactory()->enableOverrides(); } } diff -u b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php --- b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php +++ b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php @@ -21,6 +21,9 @@ if (in_array('system.site', $names)) { $event->setOverride('system.site', array('name' => 'ZOMG overridden site name')); } + if (in_array('config_override.new', $names)) { + $event->setOverride('config_override.new', array('module' => 'override')); + } } }