diff -u b/core/includes/config.inc b/core/includes/config.inc --- b/core/includes/config.inc +++ b/core/includes/config.inc @@ -24,10 +24,13 @@ * The name of the module or theme to install default configuration for. */ function config_install_default_config($type, $name) { + // Use the admin context for config importing so that any overrides do not + // change the data on import. + $free_context = drupal_container()->get('config.context.free'); // If this module defines any ConfigEntity types then create an empty // manifest file for each of them. foreach (config_get_module_config_entities($name) as $entity_info) { - config('manifest.' . $entity_info['config_prefix'])->save(); + config('manifest.' . $entity_info['config_prefix'], $free_context)->save(); } $config_dir = drupal_get_path($type, $name) . '/config'; @@ -176,7 +179,7 @@ * The storage to synchronize configuration to. */ function config_sync_changes(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) { - $target_context = drupal_container()->get('config.context.admin'); + $target_context = drupal_container()->get('config.context.free'); $factory = drupal_container()->get('config.factory'); foreach (array('delete', 'create', 'change') as $op) { foreach ($config_changes[$op] as $name) { @@ -247,9 +250,9 @@ * @todo Add support for other extension types; e.g., themes etc. */ function config_import_invoke_owner(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) { - // Use the admin context for config importing so that any global overrides do - // not pollute the import. - $admin_context = drupal_container()->get('config.context.admin'); + // Use the admin context for config importing so that any overrides do not + // change the data on import. + $free_context = drupal_container()->get('config.context.free'); // Allow modules to take over configuration change operations for // higher-level configuration data. // First pass deleted, then new, and lastly changed configuration, in order to @@ -263,11 +266,11 @@ // Validate the configuration object name before importing it. Config::validateName($name); if ($entity_type = config_get_entity_type_by_name($name)) { - $old_config = new Config($name, $target_storage, $admin_context); + $old_config = new Config($name, $target_storage, $free_context); $old_config->load(); $data = $source_storage->read($name); - $new_config = new Config($name, $source_storage, $admin_context); + $new_config = new Config($name, $source_storage, $free_context); if ($data !== FALSE) { $new_config->setData($data); } 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 @@ -42,7 +42,7 @@ * * @var \Drupal\Core\Config\Context\ContextInterface */ - protected $context; + protected $defaultContext; /** * Cached configuration objects. @@ -61,7 +61,7 @@ */ public function __construct(StorageInterface $storage, ContextInterface $context) { $this->storage = $storage; - $this->setContext($context); + $this->defaultContext = $context; } /** @@ -73,15 +73,15 @@ * (Optional) The configuration context to use. */ public function get($name, ContextInterface $context = NULL) { - if ($context) { - $this->setContext($context); + if (!$context) { + $context = $this->defaultContext; } - $cache_key = $this->getCacheKey($name); + $cache_key = $this->getCacheKey($name, $context); if (isset($this->cache[$cache_key])) { return $this->cache[$cache_key]; } - $this->cache[$cache_key] = new Config($name, $this->storage, $this->getContext()); + $this->cache[$cache_key] = new Config($name, $this->storage, $context); return $this->cache[$cache_key]->init(); } @@ -94,8 +94,8 @@ */ public function reset($name = NULL) { if ($name) { - $cache_key = $this->getCacheKey($name); - if (isset($this->cache[$cache_key])) { + // Reinitialise the configuration object in all contexts. + foreach ($this->getCacheKeys($name) as $cache_key) { $this->cache[$cache_key]->init(); } } @@ -117,8 +117,8 @@ * @todo D8: Remove after http://drupal.org/node/1865206. */ public function rename($old_name, $new_name) { - $old_cache_key = $this->getCacheKey($old_name); - $new_cache_key = $this->getCacheKey($new_name); + $old_cache_key = $this->getCacheKey($old_name, $this->defaultContext); + $new_cache_key = $this->getCacheKey($new_name, $this->defaultContext); if (isset($this->cache[$old_cache_key])) { $config = $this->cache[$old_cache_key]; // Clone the object into the existing slot. @@ -130,34 +130,21 @@ } } - /** - * Gets the default context for this factory. - * - * @return Drupal\Core\Config\Context\ContextInterface - * A configuration context instance. - */ - public function getContext() { - return $this->context; - } - - /** - * Sets the default context for this factory. - * - * @param \Drupal\Core\Config\Context\ContextInterface $context - * Context to use to get the configuration. - */ - public function setContext($context) { - $this->context = $context; - } - /* * Gets the cache key for a given config name in a particular context. * * @return string * The cache key. */ - public function getCacheKey($name) { - return $this->getContext()->getUuid() . ':' . $name; + public function getCacheKey($name, ContextInterface $context) { + return $name . '.' . $context->getUuid(); + } + + public function getCacheKeys($name) { + $cache_keys = array_keys($this->cache); + return array_filter($cache_keys, function($key) use ($name) { + return ( strpos($key, $name) !== false ); + }); } } diff -u b/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php --- b/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -58,9 +58,12 @@ ->setFactoryService(new Reference('config.context.factory')) ->setFactoryMethod('get') ->addArgument('Drupal\Core\Config\Context\GlobalConfigContext') + ->addTag('persist') ->addMethodCall('setGlobalOverride'); - $container->register('config.context.admin', 'Drupal\Core\Config\Context\ContextInterface') + // Register a config context with no overrides for use in administration + // forms, enabling modules and importing configuration. + $container->register('config.context.free', 'Drupal\Core\Config\Context\ContextInterface') ->setFactoryService(new Reference('config.context.factory')) ->setFactoryMethod('get'); 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 @@ -30,12 +30,6 @@ ); } - function setUp() { - parent::setUp(); - - config_install_default_config('module', 'config_test'); - } - /** * Tests configuration override. */ @@ -47,6 +41,27 @@ '404' => 'herp', ); + // Set globals before installing to prove that the installed file does not + // contain these values. + $conf['config_test.system']['foo'] = 'overridden'; + $conf['config_test.system']['baz'] = 'injected'; + $conf['config_test.system']['404'] = 'derp'; + drupal_container()->get('config.context')->setGlobalOverride(); + + config_install_default_config('module', 'config_test'); + + // Verify that the original configuration data exists. Have to read storage + // directly otherwise overrides will apply. + $active = $this->container->get('config.storage'); + $data = $active->read('config_test.system'); + $this->assertIdentical($data['foo'], $expected_original_data['foo']); + $this->assertFalse(isset($data['baz'])); + $this->assertIdentical($data['404'], $expected_original_data['404']); + + // Remove the $conf overrides and reset value in config.context service. + unset($conf['config_test.system']); + drupal_container()->get('config.context')->setGlobalOverride(); + // Verify that the original configuration data exists. $config = config('config_test.system'); $this->assertIdentical($config->get('foo'), $expected_original_data['foo']); @@ -105,6 +120,36 @@ $this->assertIdentical($config->get('foo'), $expected_original_data['foo']); $this->assertIdentical($config->get('baz'), $expected_original_data['baz']); $this->assertIdentical($config->get('404'), $expected_original_data['404']); + + // Set globals before importing to prove that the imported file does not + // contain these values. + $conf['config_test.system']['foo'] = 'overridden'; + $conf['config_test.system']['baz'] = 'injected'; + $conf['config_test.system']['404'] = 'derp'; + + // Write file to staging + drupal_container()->get('config.context')->setGlobalOverride(); + $staging = $this->container->get('config.storage.staging'); + $expected_new_data = array( + 'foo' => 'barbar', + '404' => 'herpderp', + ); + $staging->write('config_test.system', $expected_new_data); + + // Import changed data from staging to active. + config_import(); + $data = $active->read('config_test.system'); + + // Verify that the new configuration data exists. Have to read storage + // directly otherwise overrides will apply. + $this->assertIdentical($data['foo'], $expected_new_data['foo']); + $this->assertFalse(isset($data['baz'])); + $this->assertIdentical($data['404'], $expected_new_data['404']); + + // Verifiy the overrides are still working. + $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']); } } diff -u b/core/modules/system/system.module b/core/modules/system/system.module --- b/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -3462,7 +3462,7 @@ * @see config() */ function system_config($name) { - return config($name, drupal_container()->get('config.context.admin')); + return config($name, drupal_container()->get('config.context.free')); } /**