diff -u b/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php --- b/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -71,6 +71,9 @@ /** * The current runtime data. * + * The configuration data from storage merged with language, module and + * settings overrides. + * * @var array */ protected $overriddenData; @@ -129,7 +132,7 @@ * An event dispatcher instance to use for configuration events. * @param \Drupal\Core\Config\TypedConfigManager $typed_config * The typed configuration manager service. - * @param Drupal\Core\Language\Language $language + * @param \Drupal\Core\Language\Language $language * The language object used to override configuration data. */ public function __construct($name, StorageInterface $storage, EventDispatcher $event_dispatcher, TypedConfigManager $typed_config, Language $language = NULL) { @@ -308,7 +311,7 @@ } /** - * Sets settings.php overrides this configuration object. + * Sets settings.php overrides for this configuration object. * * The overridden data only applies to this configuration object. * @@ -330,7 +333,7 @@ * @param array $data * The overridden values of the configuration data. * - * @return Drupal\Core\Config\Config + * @return \Drupal\Core\Config\Config * The configuration object. */ public function setModuleOverride(array $data) { @@ -345,7 +348,7 @@ * @param array $data * The overridden values of the configuration data. * - * @return Drupal\Core\Config\Config + * @return \Drupal\Core\Config\Config * The configuration object. */ public function setLanguageOverride(array $data) { @@ -357,10 +360,10 @@ /** * Sets the current data for this configuration object. * - * Configuration overrides operate at three distinct layers: locale, modules - * and settings.php, with the last of these winning. Overrides in - * settings.php win over values provided by modules. Overrides provided by - * modules win over locale. + * Configuration overrides operate at three distinct layers: language, modules + * and settings.php, with the last of these taking precedence. Overrides in + * settings.php take precedence over values provided by modules. Overrides + * provided by modules take precedence over language. * * @return \Drupal\Core\Config\Config * The configuration object. @@ -665,19 +668,4 @@ } - /** - * Get configuration name for this language. - * - * It will be the same name with a prefix depending on language code: - * language.config.LANGCODE.NAME - * - * @return string - * The localized config name. - */ - public function getLanguageConfigName() { - if (!isset($this->language)) { - throw new ConfigException("No language set, cannot return language config name for '{$this->name}'"); - } - return 'language.config.' . $this->language->id . '.' . $this->getName(); - } } 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 @@ -7,9 +7,7 @@ namespace Drupal\Core\Config; -use Drupal\Core\Config\TypedConfigManager; use Drupal\Core\Language\Language; -use Drupal\Core\Config\ConfigModuleOverridesEvent; use Symfony\Component\EventDispatcher\EventDispatcher; /** @@ -28,6 +26,11 @@ class ConfigFactory { /** + * Prefix for all language configuration files. + */ + const LANGUAGE_CONFIG_PREFIX = 'language.config'; + + /** * A storage controller instance for reading and writing configuration data. * * @var \Drupal\Core\Config\StorageInterface @@ -51,14 +54,14 @@ /** * The language object used to override configuration data. * - * @var Drupal\Core\Language\Language + * @var \Drupal\Core\Language\Language */ protected $language; /** * Cached configuration objects. * - * @var array + * @var \Drupal\Core\Config\Config[] */ protected $cache = array(); @@ -79,7 +82,9 @@ * @param \Drupal\Core\Config\TypedConfigManager $typed_config * The typed configuration manager. * @param \Drupal\Core\Language\Language - * The language for this configuration. + * (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. */ public function __construct(StorageInterface $storage, EventDispatcher $event_dispatcher, TypedConfigManager $typed_config, Language $language = NULL) { $this->storage = $storage; @@ -157,16 +162,16 @@ // Pre-load remaining configuration files. if (!empty($names)) { 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))); - $moduleOverrides = $this->loadModuleOverrides($names); } else { - $language_names = array(); $moduleOverrides = array(); + $language_names = array(); $storage_data = $this->storage->readMultiple($names); } @@ -311,11 +316,14 @@ } /** - * Set the language to be injected in to Config objects. + * Set the language to be used in configuration overrides. * - * @param Language $language + * @param \Drupal\Core\Language\Language $language + * The language object to be set on the config factory. Used to override + * configuration by language. * - * @return ConfigFactory + * @return \Drupal\Core\Config\ConfigFactory + * The config factory object. */ public function setLanguage(Language $language = NULL) { $this->language = $language; @@ -323,7 +331,7 @@ } /** - * Get the language to be injected in to Config objects. + * Gets the language Used to override configuration. * * @return \Drupal\Core\Language\Language */ @@ -332,7 +340,7 @@ } /** - * Get configuration names for this language. + * Gets configuration names for this language. * * It will be the same name with a prefix depending on language code: * language.config.LANGCODE.NAME @@ -347,32 +355,34 @@ $language_names = array(); if (isset($this->language)) { foreach ($names as $name) { - if (strpos($name, 'lanuguage.config.') === 0) { - continue; + if ($language_name = $this->getLanguageConfigName($this->language->id, $name)) { + $language_names[$name] = $language_name; } - $language_names[$name] = 'language.config.' . $this->language->id . '.' . $name; } } return $language_names; } /** - * Get configuration name for this language. + * Gets configuration name for the provided language. * - * It will be the same name with a prefix depending on language code: + * The name will be the same name with a prefix depending on language code: * language.config.LANGCODE.NAME * + * @param string $langcode + * The language code. * @param string $name - * The name of the config object. + * The name of the configuration object. * - * @return string - * The localized config name. + * @return bool|string + * The configuration name for configuration object providing overrides. + * Returns false if the name already starts with the language config prefix. */ - public function getLanguageConfigName($name) { - if (!isset($this->language) || strpos($name, 'language.config.') === 0) { + public function getLanguageConfigName($langcode, $name) { + if (strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0) { return FALSE; } - return 'language.config.' . $this->language->id . '.' . $name; + return static::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.' . $name; } } diff -u b/core/lib/Drupal/Core/Config/ConfigModuleOverridesEvent.php b/core/lib/Drupal/Core/Config/ConfigModuleOverridesEvent.php --- b/core/lib/Drupal/Core/Config/ConfigModuleOverridesEvent.php +++ b/core/lib/Drupal/Core/Config/ConfigModuleOverridesEvent.php @@ -1,10 +1,19 @@ names; } /** - * Get configuration language. + * Gets configuration language. + * + * @return \Drupal\Core\Language\Language + * The configuration language object. */ public function getLanguage() { return $this->language; @@ -58,17 +73,35 @@ /** * Get configuration overrides. + * + * @return array. + * The array of configuration overrides. */ public function getOverrides() { return $this->overrides; } /** - * Set a configuration override for the given name. + * Sets a configuration override for the given name. + * + * @param string $name + * The configuration object name to override. + * @param array $values + * The values in the configuration object to override. + * + * @return self + * The ConfigModuleOverridesEvent object. */ - public function setOverride($name, $value) { + public function setOverride($name, array $values) { if (in_array($name, $this->names)) { - $this->overrides[$name] = $value; + if (isset($this->overrides[$name])) { + // Existing overrides take precedence since these will have been added + // by events with a higher priority. + $this->overrides[$name] = NestedArray::mergeDeepArray(array($values, $this->overrides[$name]), TRUE); + } + else { + $this->overrides[$name] = $values; + } } return $this; } diff -u b/core/lib/Drupal/Core/Form/ConfigFormBase.php b/core/lib/Drupal/Core/Form/ConfigFormBase.php --- b/core/lib/Drupal/Core/Form/ConfigFormBase.php +++ b/core/lib/Drupal/Core/Form/ConfigFormBase.php @@ -69,12 +69,14 @@ /** * {@inheritdoc} + * + * Overrides \Drupal\Core\Form\FormBase::config() so that configuration is + * returned override free. This ensures that overrides do not pollute saved + * configuration. */ protected function config($name) { - if (!$this->configFactory) { - $container = $this->container(); - $this->configFactory = $container->get('config.factory'); - $this->configFactory->disableOverrides(); - } - return $this->configFactory->get($name); + $this->configFactory->disableOverrides(); + $config = $this->configFactory->get($name); + $this->configFactory->enableOverrides(); + return $config; } } diff -u b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php /dev/null --- b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php +++ /dev/null @@ -1,66 +0,0 @@ - 'Locale override', - 'description' => 'Confirm that locale overrides work', - 'group' => 'Configuration', - ); - } - - public function setUp() { - parent::setUp(); - config_install_default_config('module', 'config_test'); - config_install_default_config('module', 'locale'); - \Drupal::configFactory()->setLanguage(language_default()); - } - - /** - * Tests locale override based on language. - */ - function testConfigLocaleLanguageOverride() { - $config = \Drupal::config('config_test.system'); - $this->assertIdentical($config->get('foo'), 'en bar'); - - language_save(new Language(array( - 'name' => 'French', - 'id' => 'fr', - ))); - language_save(new Language(array( - 'name' => 'German', - 'id' => 'de', - ))); - - \Drupal::configFactory()->setLanguage(language_load('fr')); - $config = \Drupal::config('config_test.system'); - $this->assertIdentical($config->get('foo'), 'fr bar'); - - \Drupal::configFactory()->setLanguage(language_load('de')); - $config = \Drupal::config('config_test.system'); - $this->assertIdentical($config->get('foo'), 'de bar'); - } -} - 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 @@ -7,14 +7,14 @@ namespace Drupal\config\Tests; -use Drupal\simpletest\WebTestBase; +use Drupal\simpletest\DrupalUnitTestBase; /** - * Tests importing configuration from files into active store. + * Tests module overrides of configuration using event subscribers. */ -class ConfigModuleOverridesTest extends WebTestBase { +class ConfigModuleOverridesTest extends DrupalUnitTestBase { - public static $modules = array('config', 'config_test'); + public static $modules = array('system', 'config', 'config_override'); public static function getInfo() { return array( @@ -32,16 +32,20 @@ + $overridden_slogan = 'Yay for overrides!'; + $non_overridden_slogan = 'Yay for defaults!'; $config_factory = $this->container->get('config.factory'); $config_factory ->get($name) ->set('name', $non_overridden_name) + ->set('slogan', $non_overridden_slogan) ->save(); $config_factory->disableOverrides(); $this->assertEqual($non_overridden_name, $config_factory->get('system.site')->get('name')); + $this->assertEqual($non_overridden_slogan, $config_factory->get('system.site')->get('slogan')); $config_factory->enableOverrides(); $this->assertEqual($overridden_name, $config_factory->get('system.site')->get('name')); + $this->assertEqual($overridden_slogan, $config_factory->get('system.site')->get('slogan')); unset($GLOBALS['config_test_run_module_overrides']); } } - reverted: --- b/core/modules/config/tests/config_test/config_test.services.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - config_test_config_subscriber: - class: Drupal\config_test\EventSubscriber\ConfigModuleOverrideSubscriber - tags: - - { name: event_subscriber } - reverted: --- b/core/modules/config/tests/config_test/lib/Drupal/config_test/EventSubscriber/ConfigModuleOverrideSubscriber.php +++ /dev/null @@ -1,42 +0,0 @@ -getNames(); - $language = $event->getLanguage(); - $overrides = $event->getOverrides(); - $overridden_name = 'ZOMG overridden site name'; - - if (in_array('system.site', $names)) { - $event->setOverride('system.site', array('name' => $overridden_name)); - } - } - } - - /** - * Registers the methods in this class that should be listeners. - * - * @return array - * An array of event listener definitions. - */ - static function getSubscribedEvents() { - $events['config.module.overrides'][] = array('onConfigLoadMultiple', 40); - return $events; - } -} - diff -u b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php --- b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php @@ -214,7 +214,8 @@ foreach ($this->mapper->getConfigNames() as $name) { // Set configuration values based on form submission and source values. $base_config = $this->config($name); - $translation_config = $this->config('locale.config.' . $this->language->id . '.' . $name); + $translation_config_name = $this->configFactory->getLanguageConfigName($this->language->id, $name); + $translation_config = $this->config($translation_config_name); $locations = $this->localeStorage->getLocations(array('type' => 'configuration', 'name' => $name)); $this->setConfig($this->language, $base_config, $translation_config, $form_values[$name], !empty($locations)); diff -u b/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php /dev/null --- b/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php +++ /dev/null @@ -1,83 +0,0 @@ -languageManager = $language_manager; - $this->configFactory = $config_factory; - } - - /** - * Sets the negotiated interface language on the configuration factory. - * - * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event - * Kernel event to respond to. - */ - public function onKernelRequestSetDefaultConfigLanguage(GetResponseEvent $event) { - if ($this->languageManager->isMultiLingual()) { - $this->configFactory->setLanguage($this->languageManager->getLanguage()); - } - } - - /** - * Get configuration name for this language. - * - * It will be the same name with a prefix depending on language code: - * locale.config.LANGCODE.NAME - * - * @param string $name - * The name of the config object. - * @param \Drupal\Core\Language\Language $language - * The language object. - * - * @return string - * The localized config name. - */ - public function getLocaleConfigName($name, Language $language) { - return 'locale.config.' . $language->id . '.' . $name; - } - - /** - * Implements EventSubscriberInterface::getSubscribedEvents(). - */ - static function getSubscribedEvents() { - $events[KernelEvents::REQUEST][] = array('onKernelRequestSetDefaultConfigLanguage', 48); - return $events; - } -} - diff -u b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php --- b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php @@ -171,14 +171,15 @@ $this->assertEqual($property->getValue(), $image_style_label, 'Got the right translation for image style name after translation'); // Quick test to ensure translation file exists. - $this->assertEqual(\Drupal::config('locale.config.xx.image.style.medium')->get('label'), $image_style_label); + $language_config_name = \Drupal::configFactory()->getLanguageConfigName('xx', 'image.style.medium'); + $this->assertEqual(\Drupal::config($language_config_name)->get('label'), $image_style_label); // Uninstall the module. $this->drupalPostForm('admin/modules/uninstall', array('uninstall[image]' => "image"), t('Uninstall')); $this->drupalPostForm(NULL, array(), t('Uninstall')); // Ensure that the translated configuration has been removed. - $this->assertFalse(\Drupal::config('locale.config.xx.image.style.medium')->get('label'), 'Translated configuration for image module removed.'); + $this->assertFalse(\Drupal::config($language_config_name)->get('label'), 'Translated configuration for image module removed.'); // Translate default category using the UI so configuration is refreshed. $category_label = $this->randomName(20); diff -u b/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml --- b/core/modules/locale/locale.services.yml +++ b/core/modules/locale/locale.services.yml @@ -1,9 +1,4 @@ services: - locale_config_subscriber: - class: Drupal\locale\LocaleConfigSubscriber - tags: - - { name: event_subscriber } - arguments: ['@language_manager', '@config.factory'] paramconverter.configentity_admin: class: Drupal\locale\ParamConverter\LocaleAdminPathConfigEntityConverter tags: @@ -11,7 +6,7 @@ arguments: ['@entity.manager', '@config.factory'] locale.config.typed: class: Drupal\locale\LocaleConfigManager - arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage'] + arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@config.factory'] locale.storage: class: Drupal\locale\StringDatabaseStorage arguments: ['@database'] only in patch2: unchanged: --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php @@ -0,0 +1,65 @@ + 'Language override', + 'description' => 'Confirm that language overrides work', + 'group' => 'Configuration', + ); + } + + public function setUp() { + parent::setUp(); + config_install_default_config('module', 'config_test'); + config_install_default_config('module', 'locale'); + \Drupal::configFactory()->setLanguage(language_default()); + } + + /** + * Tests locale override based on language. + */ + function testConfigLanguageOverride() { + $config = \Drupal::config('config_test.system'); + $this->assertIdentical($config->get('foo'), 'en bar'); + + language_save(new Language(array( + 'name' => 'French', + 'id' => 'fr', + ))); + language_save(new Language(array( + 'name' => 'German', + 'id' => 'de', + ))); + + \Drupal::configFactory()->setLanguage(language_load('fr')); + $config = \Drupal::config('config_test.system'); + $this->assertIdentical($config->get('foo'), 'fr bar'); + + \Drupal::configFactory()->setLanguage(language_load('de')); + $config = \Drupal::config('config_test.system'); + $this->assertIdentical($config->get('foo'), 'de bar'); + } +} + only in patch2: unchanged: --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverrideWebTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\config\Tests\ConfigLocaleOverrideWebTest. + * Contains \Drupal\config\Tests\ConfigLanguageOverrideWebTest. */ namespace Drupal\config\Tests; @@ -12,14 +12,14 @@ /** * Tests language overrides in configuration through the request. */ -class ConfigLocaleOverrideWebTest extends WebTestBase { +class ConfigLanguageOverrideWebTest extends WebTestBase { - public static $modules = array('locale', 'language', 'system'); + public static $modules = array('language', 'system'); public static function getInfo() { return array( - 'name' => 'Locale overrides through the request', - 'description' => 'Tests locale overrides applied through the website.', + 'name' => 'Language overrides through the request', + 'description' => 'Tests language overrides applied through the website.', 'group' => 'Configuration', ); } @@ -47,7 +47,8 @@ function testSiteNameTranslation() { $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language')); // Save an override for the XX language. - \Drupal::config('locale.config.xx.system.site')->set('name', 'XX site name')->save(); + $config_name = \Drupal::configFactory()->getLanguageConfigName('xx', 'system.site'); + \Drupal::config($config_name)->set('name', 'XX site name')->save(); $this->drupalLogout(); only in patch2: unchanged: --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php @@ -0,0 +1,103 @@ + 'Override priority', + 'description' => 'Tests that language, module and settings.php are applied in the correct order.', + 'group' => 'Configuration', + ); + } + + public function testOverridePriorities() { + global $conf; + $GLOBALS['config_test_run_module_overrides'] = FALSE; + + $non_overridden_mail = 'site@example.com'; + $language_overridden_mail = 'french@example.com'; + + $language_overridden_name = 'French site name'; + $module_overridden_name = 'ZOMG overridden site name'; + $non_overridden_name = 'ZOMG this name is on disk mkay'; + + $module_overridden_slogan = 'Yay for overrides!'; + $non_overridden_slogan = 'Yay for defaults!'; + + /** @var \Drupal\Core\Config\ConfigFactory $config_factory */ + $config_factory = $this->container->get('config.factory'); + $config_factory + ->get('system.site') + ->set('name', $non_overridden_name) + ->set('slogan', $non_overridden_slogan) + ->set('mail', $non_overridden_mail) + ->set('weight_select_max', 50) + ->save(); + + // Ensure that no overrides are applying. + $this->assertEqual($non_overridden_name, $config_factory->get('system.site')->get('name')); + $this->assertEqual($non_overridden_slogan, $config_factory->get('system.site')->get('slogan')); + $this->assertEqual($non_overridden_mail, $config_factory->get('system.site')->get('mail')); + $this->assertEqual(50, $config_factory->get('system.site')->get('weight_select_max')); + + // Override using language. + $language = new Language(array( + 'name' => 'French', + 'id' => 'fr', + )); + $config_factory->setLanguage($language); + $language_config_name = $config_factory->getLanguageConfigName($language->id, 'system.site'); + $config_factory + ->get($language_config_name) + ->set('name', $language_overridden_name) + ->set('mail', $language_overridden_mail) + ->save(); + + $this->assertEqual($language_overridden_name, $config_factory->get('system.site')->get('name')); + $this->assertEqual($non_overridden_slogan, $config_factory->get('system.site')->get('slogan')); + $this->assertEqual($language_overridden_mail, $config_factory->get('system.site')->get('mail')); + $this->assertEqual(50, $config_factory->get('system.site')->get('weight_select_max')); + + // Enable module overrides. Do not override system.site:mail to prove that + // the language override still applies. + $GLOBALS['config_test_run_module_overrides'] = TRUE; + $config_factory->reset('system.site'); + $this->assertEqual($module_overridden_name, $config_factory->get('system.site')->get('name')); + $this->assertEqual($module_overridden_slogan, $config_factory->get('system.site')->get('slogan')); + $this->assertEqual($language_overridden_mail, $config_factory->get('system.site')->get('mail')); + $this->assertEqual(50, $config_factory->get('system.site')->get('weight_select_max')); + + // Configure a global override to simulate overriding using settings.php. Do + // not override system.site:mail or system.site:slogan to prove that the + // language and module overrides still apply. + $conf['system.site']['name'] = 'Site name global conf override'; + $config_factory->reset('system.site'); + $this->assertEqual('Site name global conf override', $config_factory->get('system.site')->get('name')); + $this->assertEqual($module_overridden_slogan, $config_factory->get('system.site')->get('slogan')); + $this->assertEqual($language_overridden_mail, $config_factory->get('system.site')->get('mail')); + $this->assertEqual(50, $config_factory->get('system.site')->get('weight_select_max')); + + $config_factory->disableOverrides(); + $this->assertEqual($non_overridden_name, $config_factory->get('system.site')->get('name')); + $this->assertEqual($non_overridden_slogan, $config_factory->get('system.site')->get('slogan')); + $this->assertEqual($non_overridden_mail, $config_factory->get('system.site')->get('mail')); + $this->assertEqual(50, $config_factory->get('system.site')->get('weight_select_max')); + + unset($GLOBALS['config_test_run_module_overrides']); + } +} only in patch2: unchanged: --- /dev/null +++ b/core/modules/config/tests/config_override/config_override.info.yml @@ -0,0 +1,6 @@ +name: 'Configuration override test' +type: module +package: Testing +version: VERSION +core: 8.x +hidden: true only in patch2: unchanged: --- /dev/null +++ b/core/modules/config/tests/config_override/config_override.module @@ -0,0 +1,6 @@ +getNames(); + if (in_array('system.site', $names)) { + $event->setOverride('system.site', array( + 'name' => 'Should not apply because of higher priority listener', + // This override should apply because it is not overridden by the + // higher priority listener. + 'slogan' => 'Yay for overrides!', + )); + } + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events['config.module.overrides'][] = array('onConfigModuleOverride', 35); + return $events; + } +} + only in patch2: unchanged: --- /dev/null +++ b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php @@ -0,0 +1,38 @@ +getNames(); + if (in_array('system.site', $names)) { + $event->setOverride('system.site', array('name' => 'ZOMG overridden site name')); + } + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events['config.module.overrides'][] = array('onConfigModuleOverride', 40); + return $events; + } +} + only in patch2: unchanged: --- a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php @@ -137,7 +137,8 @@ public function buildForm(array $form, array &$form_state, Request $request = NU */ public function submitForm(array &$form, array &$form_state) { foreach ($this->mapper->getConfigNames() as $name) { - $this->configStorage->delete('locale.config.' . $this->language->id . '.' . $name); + $config_name = $this->configFactory->getLanguageConfigName($this->language->id, $name); + $this->configStorage->delete($config_name); } // Flush all persistent caches. only in patch2: unchanged: --- a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php @@ -178,7 +178,8 @@ public function testSourceValueDuplicateSave() { // Read overridden file from active config. $file_storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); - $config_parsed = $file_storage->read('locale.config.fr.system.site'); + $language_config_name = \Drupal::configFactory()->getLanguageConfigName('fr', 'system.site'); + $config_parsed = $file_storage->read($language_config_name); // Expect both name and slogan in language specific file. $expected = array( @@ -199,7 +200,7 @@ public function testSourceValueDuplicateSave() { ); $this->drupalPostForm(NULL, $edit, t('Save translation')); $this->assertRaw(t('Successfully updated @language translation.', array('@language' => 'French'))); - $config_parsed = $file_storage->read('locale.config.fr.system.site'); + $config_parsed = $file_storage->read($language_config_name); // Expect only slogan in language specific file. $expected = array('slogan' => 'FR ' . $site_slogan); @@ -213,7 +214,7 @@ public function testSourceValueDuplicateSave() { 'config_names[system.site][slogan][translation]' => $site_slogan, ); $this->drupalPostForm(NULL, $edit, t('Save translation')); - $config_parsed = $file_storage->read('locale.config.fr.system.site'); + $config_parsed = $file_storage->read($language_config_name); // Expect no language specific file. $this->assertFalse($config_parsed); @@ -284,7 +285,8 @@ public function testContactConfigEntityTranslation() { $this->drupalPostForm($translation_page_url, $edit, t('Save translation')); // Expect translated values in language specific file. - $config_parsed = $file_storage->read('locale.config.'. $langcode . '.contact.category.feedback'); + $language_config_name = \Drupal::configFactory()->getLanguageConfigName($langcode, 'contact.category.feedback'); + $config_parsed = $file_storage->read($language_config_name); $expected = array( 'label' => 'Website feedback - ' . $langcode, 'reply' => 'Thank you for your mail - ' . $langcode, @@ -347,7 +349,8 @@ public function testContactConfigEntityTranslation() { $this->assertNoLinkByHref("$translation_base_url/$langcode/delete"); // Expect no language specific file present anymore. - $config_parsed = $file_storage->read('locale.config.'. $langcode . '.config.category.feedback'); + $language_config_name = \Drupal::configFactory()->getLanguageConfigName($langcode, 'contact.category.feedback'); + $config_parsed = $file_storage->read($language_config_name); $this->assertFalse($config_parsed); } @@ -414,7 +417,8 @@ public function testDateFormatTranslation() { $this->drupalPostForm($translation_page_url, $edit, t('Save translation')); // Get translation and check we've got the right value. - $config_parsed = $file_storage->read('locale.config.fr.system.date_format.' . $id); + $language_config_name = \Drupal::configFactory()->getLanguageConfigName('fr', 'system.date_format.' . $id); + $config_parsed = $file_storage->read($language_config_name); $expected = array( 'label' => $id . ' - FR', 'pattern' => array('php' => 'D'), only in patch2: unchanged: --- a/core/modules/language/language.services.yml +++ b/core/modules/language/language.services.yml @@ -5,3 +5,8 @@ services: tags: - { name: path_processor_inbound, priority: 300 } - { name: path_processor_outbound, priority: 100 } + language_config_subscriber: + class: Drupal\language\LanguageConfigSubscriber + tags: + - { name: event_subscriber } + arguments: ['@language_manager', '@config.factory'] only in patch2: unchanged: --- /dev/null +++ b/core/modules/language/lib/Drupal/language/LanguageConfigSubscriber.php @@ -0,0 +1,68 @@ +languageManager = $language_manager; + $this->configFactory = $config_factory; + } + + /** + * Sets the negotiated interface language on the configuration factory. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * Kernel event to respond to. + */ + public function onKernelRequestSetDefaultConfigLanguage(GetResponseEvent $event) { + if ($this->languageManager->isMultiLingual()) { + $this->configFactory->setLanguage($this->languageManager->getLanguage()); + } + } + + /** + * Implements EventSubscriberInterface::getSubscribedEvents(). + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('onKernelRequestSetDefaultConfigLanguage', 48); + return $events; + } +} + only in patch2: unchanged: --- a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php @@ -10,6 +10,7 @@ use Drupal\Core\Language\Language; use Drupal\Core\Config\TypedConfigManager; use Drupal\Core\Config\StorageInterface; +use Drupal\Core\Config\ConfigFactory; /** * Manages localized configuration type plugins. @@ -36,6 +37,13 @@ class LocaleConfigManager extends TypedConfigManager { protected $translations; /** + * The configuration factory. + * + * @var \Drupal\Core\Config\ConfigFactory + */ + protected $configFactory; + + /** * Creates a new typed configuration manager. * * @param \Drupal\Core\Config\StorageInterface $configStorage @@ -47,12 +55,15 @@ class LocaleConfigManager extends TypedConfigManager { * data. * @param \Drupal\locale\StringStorageInterface $localeStorage * The locale storage to use for reading string translations. + * @param \Drupal\Core\Config\ConfigFactory $config_factory + * The configuration factory */ - public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage) { + public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, ConfigFactory $config_factory) { // Note we use the install storage for the parent constructor. parent::__construct($configStorage, $schemaStorage); $this->installStorage = $installStorage; $this->localeStorage = $localeStorage; + $this->configFactory = $config_factory; } /** @@ -119,7 +130,7 @@ protected function compareConfigData(array $default, $updated) { * Configuration data to be saved, that will be only the translated values. */ public function saveTranslationData($name, $langcode, array $data) { - $locale_name = self::localeConfigName($langcode, $name); + $locale_name = $this->configFactory->getLanguageConfigName($langcode, $name); $this->configStorage->write($locale_name, $data); } @@ -132,7 +143,7 @@ public function saveTranslationData($name, $langcode, array $data) { * Language code. */ public function deleteTranslationData($name, $langcode) { - $locale_name = self::localeConfigName($langcode, $name); + $locale_name = $this->configFactory->getLanguageConfigName($langcode, $name); $this->configStorage->delete($locale_name); } @@ -206,7 +217,7 @@ public function getStringNames(array $lids) { * Language code to delete. */ public function deleteLanguageTranslations($langcode) { - $locale_name = self::localeConfigName($langcode); + $locale_name = ConfigFactory::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.'; foreach ($this->configStorage->listAll($locale_name) as $name) { $this->configStorage->delete($name); } @@ -291,24 +302,9 @@ public function translateString($name, $langcode, $source, $context) { * A boolean indicating if a language has configuration translations. */ public function hasTranslation($name, Language $language) { - $locale_name = static::localeConfigName($language->id, $name); + $locale_name = $this->configFactory->getLanguageConfigName($language->id, $name); $translation = $this->configStorage->read($locale_name); return !empty($translation); } - /** - * Provides configuration data location for given langcode and name. - * - * @param string $langcode - * The language code. - * @param string|null $name - * Name of the original configuration. Set to NULL to get the name prefix - * for all $langcode overrides. - * - * @return string - */ - public static function localeConfigName($langcode, $name = NULL) { - return rtrim('locale.config.' . $langcode . '.' . $name, '.'); - } - } only in patch2: unchanged: --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php @@ -46,7 +46,8 @@ public function testHasTranslation() { $this->container->get('config.storage.installer'), $this->container->get('config.storage.schema'), $this->container->get('config.storage.installer'), - $this->container->get('locale.storage') + $this->container->get('locale.storage'), + $this->container->get('config.factory') ); $language = new Language(array('id' => 'de')); only in patch2: unchanged: --- a/core/modules/locale/locale.install +++ b/core/modules/locale/locale.install @@ -947,9 +947,9 @@ function locale_update_8016() { // Fetch all date types from {date_format_type}. $result = db_query('SELECT * FROM {date_format_locale}'); foreach ($result as $format) { - $language = $format->language; // Create config objects for the language if not yet done. - \Drupal::config("locale.config.$language.system.date_format." . $format->type) + $config_name = \Drupal::configFactory()->getLanguageConfigName($format->language, 'system.date_format.' . $format->type); + \Drupal::config($config_name) ->set('pattern.php', $format->format) ->save(); }