diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php index 1ff4046..eddb7fa 100644 --- a/core/lib/Drupal/Core/Config/CachedStorage.php +++ b/core/lib/Drupal/Core/Config/CachedStorage.php @@ -67,7 +67,7 @@ public function exists($name) { * Implements Drupal\Core\Config\StorageInterface::read(). */ public function read($name) { - if ($cache = $this->cache->get($name)) { + if ($cache = $this->cache->get($this->getCacheKey($name))) { // The cache contains either the cached configuration data or FALSE // if the configuration file does not exist. return $cache->data; @@ -75,7 +75,7 @@ public function read($name) { // Read from the storage on a cache miss and cache the data. Also cache // information about missing configuration objects. $data = $this->storage->read($name); - $this->cache->set($name, $data); + $this->cache->set($this->getCacheKey($name), $data); return $data; } @@ -87,6 +87,7 @@ public function readMultiple(array $names) { // The names array is passed by reference and will only contain the names of // config object not found after the method call. // @see \Drupal\Core\Cache\CacheBackendInterface::getMultiple() + $names = $this->getCacheKeys($names); $cached_list = $this->cache->getMultiple($names); if (!empty($names)) { @@ -94,13 +95,13 @@ public function readMultiple(array $names) { // Cache configuration objects that were loaded from the storage, cache // missing configuration objects as an explicit FALSE. foreach ($names as $name) { - $this->cache->set($name, isset($list[$name]) ? $list[$name] : FALSE); + $this->cache->set($this->getCacheKey($name), isset($list[$name]) ? $list[$name] : FALSE); } } // Add the configuration objects from the cache to the list. foreach ($cached_list as $name => $cache) { - $list[$name] = $cache->data; + $list[$this->getNameFromCacheKey($name)] = $cache->data; } // Ensure that only existing configuration objects are returned, filter out @@ -115,7 +116,7 @@ public function write($name, array $data) { if ($this->storage->write($name, $data)) { // While not all written data is read back, setting the cache instead of // just deleting it avoids cache rebuild stampedes. - $this->cache->set($name, $data); + $this->cache->set($this->getCacheKey($name), $data); Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE)); $this->findByPrefixCache = array(); return TRUE; @@ -130,7 +131,7 @@ public function delete($name) { // If the cache was the first to be deleted, another process might start // rebuilding the cache before the storage is gone. if ($this->storage->delete($name)) { - $this->cache->delete($name); + $this->cache->delete($this->getCacheKey($name)); Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE)); $this->findByPrefixCache = array(); return TRUE; @@ -145,8 +146,8 @@ public function rename($name, $new_name) { // If the cache was the first to be deleted, another process might start // rebuilding the cache before the storage is renamed. if ($this->storage->rename($name, $new_name)) { - $this->cache->delete($name); - $this->cache->delete($new_name); + $this->cache->delete($this->getCacheKey($name)); + $this->cache->delete($this->getCacheKey($new_name)); Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE)); $this->findByPrefixCache = array(); return TRUE; @@ -199,13 +200,14 @@ protected function findByPrefix($prefix) { if (!isset($this->findByPrefixCache[$prefix])) { // The : character is not allowed in config file names, so this can not // conflict. - if ($cache = $this->cache->get('find:' . $prefix)) { + $cache_key = $this->getCacheKey('find:' . $prefix); + if ($cache = $this->cache->get($cache_key)) { $this->findByPrefixCache[$prefix] = $cache->data; } else { $this->findByPrefixCache[$prefix] = $this->storage->listAll($prefix); $this->cache->set( - 'find:' . $prefix, + $cache_key, $this->findByPrefixCache[$prefix], Cache::PERMANENT, array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE) @@ -221,7 +223,7 @@ protected function findByPrefix($prefix) { public function deleteAll($prefix = '') { // If the cache was the first to be deleted, another process might start // rebuilding the cache before the storage is renamed. - $cids = $this->storage->listAll($prefix); + $cids = $this->getCacheKeys($this->storage->listAll($prefix)); if ($this->storage->deleteAll($prefix)) { $this->cache->deleteMultiple($cids); return TRUE; @@ -235,4 +237,43 @@ public function deleteAll($prefix = '') { public function resetListCache() { $this->findByPrefixCache = array(); } + + /** + * Gets the cache key for a configuration object name. + * + * @param string $name + * The configuration object name. + * + * @return string + * The cache key. + */ + protected function getCacheKey($name) { + return $name; + } + + /** + * Gets the cache keys for an array of configuration object names. + * + * @param array $names + * The configuration object names. + * + * @return array + * An array of cache keys. + */ + protected function getCacheKeys(array $names) { + return $names; + } + + /** + * Converts a cache key into a configuration object name. + * + * @param string $key + * The cache key. + * + * @return string + * The configuration object name. + */ + protected function getNameFromCacheKey($key) { + return $key; + } } diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index e000200..e864af2 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -15,7 +15,6 @@ use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\TypedData\Type\FloatInterface; use Drupal\Core\TypedData\Type\IntegerInterface; -use Drupal\Core\Language\Language; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -43,13 +42,6 @@ class Config extends DependencySerialization { protected $eventDispatcher; /** - * The language object used to override configuration data. - * - * @var Drupal\Core\Language\Language - */ - protected $language; - - /** * The name of the configuration object. * * @var string @@ -80,21 +72,14 @@ class Config extends DependencySerialization { /** * The current runtime data. * - * The configuration data from storage merged with language, module and - * settings overrides. + * The configuration data from storage merged with module and settings + * overrides. * * @var array */ protected $overriddenData; /** - * The current language overrides. - * - * @var array - */ - protected $languageOverrides; - - /** * The current module overrides. * * @var array @@ -130,19 +115,17 @@ class Config extends DependencySerialization { * @param \Drupal\Core\Config\StorageInterface $storage * A storage controller object to use for reading and writing the * configuration data. - * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher - * 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 - * The language object used to override configuration data. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * An event dispatcher instance to use for configuration events. Defaults to + * NULL which allows usage without firing events. */ - public function __construct($name, StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManager $typed_config, Language $language = NULL) { + public function __construct($name, StorageInterface $storage, TypedConfigManager $typed_config, EventDispatcherInterface $event_dispatcher = NULL) { $this->name = $name; $this->storage = $storage; $this->eventDispatcher = $event_dispatcher; $this->typedConfigManager = $typed_config; - $this->language = $language; } /** @@ -156,7 +139,6 @@ public function __construct($name, StorageInterface $storage, EventDispatcherInt */ public function initWithData(array $data) { $this->settingsOverrides = array(); - $this->languageOverrides = array(); $this->moduleOverrides = array(); $this->isNew = FALSE; $this->replaceData($data); @@ -337,36 +319,19 @@ public function setModuleOverride(array $data) { } /** - * Sets language overrides for this configuration object. - * - * @param array $data - * The overridden values of the configuration data. - * - * @return \Drupal\Core\Config\Config - * The configuration object. - */ - public function setLanguageOverride(array $data) { - $this->languageOverrides = $data; - $this->resetOverriddenData(); - return $this; - } - - /** * Sets the current data for this configuration object. * - * 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. + * Configuration overrides operate at two distinct layers: modules and + * settings.php, with the last of these taking precedence. Overrides in + * settings.php take precedence over values provided by modules. Precedence + * or different module overrides is determined by the priority of the + * config.factory.override tagged service. * * @return \Drupal\Core\Config\Config * The configuration object. */ protected function setOverriddenData() { $this->overriddenData = $this->data; - if (isset($this->languageOverrides) && is_array($this->languageOverrides)) { - $this->overriddenData = NestedArray::mergeDeepArray(array($this->overriddenData, $this->languageOverrides), TRUE); - } if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) { $this->overriddenData = NestedArray::mergeDeepArray(array($this->overriddenData, $this->moduleOverrides), TRUE); } @@ -458,7 +423,9 @@ public function save() { $this->storage->write($this->name, $this->data); $this->isNew = FALSE; - $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this)); + if (isset($this->eventDispatcher)) { + $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this)); + } $this->originalData = $this->data; return $this; } @@ -475,7 +442,9 @@ public function delete() { $this->storage->delete($this->name); $this->isNew = TRUE; $this->resetOverriddenData(); - $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this)); + if (isset($this->eventDispatcher)) { + $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this)); + } $this->originalData = $this->data; return $this; } @@ -586,15 +555,6 @@ protected function castValue($key, $value) { } /** - * Returns the language object for this Config object. - * - * @return \Drupal\Core\Language\Language - */ - public function getLanguage() { - return $this->language; - } - - /** * Gets the raw data without overrides. * * @return array @@ -625,9 +585,6 @@ public function getOriginal($key = '', $apply_overrides = TRUE) { $original_data = $this->originalData; if ($apply_overrides) { // Apply overrides. - if (isset($this->languageOverrides) && is_array($this->languageOverrides)) { - $original_data = NestedArray::mergeDeepArray(array($original_data, $this->languageOverrides), TRUE); - } if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) { $original_data = NestedArray::mergeDeepArray(array($original_data, $this->moduleOverrides), TRUE); } diff --git a/core/lib/Drupal/Core/Config/ConfigEvents.php b/core/lib/Drupal/Core/Config/ConfigEvents.php index 839b189..48f4eeb 100644 --- a/core/lib/Drupal/Core/Config/ConfigEvents.php +++ b/core/lib/Drupal/Core/Config/ConfigEvents.php @@ -35,13 +35,6 @@ const RENAME = 'config.rename'; /** - * Name of event fired when collecting overrides for configuration objects. - * - * @see \Drupal\Core\Config\ConfigFactory::loadModuleOverrides(). - */ - const MODULE_OVERRIDES = 'config.module.overrides'; - - /** * Name of event fired when validating in the configuration import process. * * @see \Drupal\Core\Config\ConfigImporter::validate(). diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index 3d26c78..64b8cbe 100644 --- a/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\Language\Language; -use Drupal\Core\Language\LanguageDefault; -use Symfony\Component\EventDispatcher\EventDispatcher; +use Drupal\Component\Utility\NestedArray; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -50,13 +48,6 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface protected $useOverrides = TRUE; /** - * The language object used to override configuration data. - * - * @var \Drupal\Core\Language\Language - */ - protected $language; - - /** * Cached configuration objects. * * @var \Drupal\Core\Config\Config[] @@ -71,6 +62,20 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface protected $typedConfigManager; /** + * An array of config factory override objects grouped by priority. + * + * @var array + */ + protected $configFactoryOverrides = array(); + + /** + * An array of sorted config factory override objects. + * + * @var array|\Drupal\Core\Config\ConfigFactoryOverrideInterface[] + */ + protected $sortedConfigFactoryOverrides; + + /** * Constructs the Config factory. * * @param \Drupal\Core\Config\StorageInterface $storage @@ -118,23 +123,13 @@ public function get($name) { // If the configuration object does not exist in the configuration // storage or static cache create a new object and add it to the static // cache. - $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->typedConfigManager, $this->eventDispatcher); - 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]); + if ($this->useOverrides) { + // Get and apply any overrides. + $overrides = $this->loadOverrides(array($name)); + if (isset($overrides[$name])) { + $this->cache[$cache_key]->setModuleOverride($overrides[$name]); } // Apply any settings.php overrides. if (isset($GLOBALS['config'][$name])) { @@ -166,38 +161,19 @@ public function loadMultiple(array $names) { if (!empty($names)) { // Initialise override information. $module_overrides = array(); - $language_names = array(); - - if ($this->useOverrides) { - // 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))); + $storage_data = $this->storage->readMultiple($names); if ($this->useOverrides && !empty($storage_data)) { - // Only fire module override event if we have configuration to override. - $module_overrides = $this->loadModuleOverrides($names); + // Only get module overrides if we have configuration to override. + $module_overrides = $this->loadOverrides($names); } foreach ($storage_data as $name => $data) { - if (in_array($name, $language_names)) { - // 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] = new Config($name, $this->storage, $this->typedConfigManager, $this->eventDispatcher); $this->cache[$cache_key]->initWithData($data); - 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 ($this->useOverrides) { if (isset($module_overrides[$name])) { $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]); } @@ -221,10 +197,14 @@ public function loadMultiple(array $names) { * @return array * An array of overrides keyed by the configuration object name. */ - protected function loadModuleOverrides(array $names) { - $configOverridesEvent = new ConfigModuleOverridesEvent($names, $this->language); - $this->eventDispatcher->dispatch(ConfigEvents::MODULE_OVERRIDES, $configOverridesEvent); - return $configOverridesEvent->getOverrides(); + protected function loadOverrides(array $names) { + $overrides = array(); + foreach ($this->getSortedConfigFactoryOverrides() as $override) { + // Existing overrides take precedence since these will have been added + // by events with a higher priority. + $overrides = NestedArray::mergeDeepArray(array($override->loadOverrides($names), $overrides), TRUE); + } + return $overrides; } /** @@ -268,11 +248,14 @@ public function rename($old_name, $new_name) { * {@inheritdoc} */ public function getCacheKey($name) { - $can_override = $this->canOverride($name); - $cache_key = $name . ':' . ($can_override ? 'overrides' : 'raw'); - - if ($can_override && isset($this->language)) { - $cache_key = $cache_key . ':' . $this->language->id; + if ($this->useOverrides) { + $cache_key = $name . ':overrides'; + foreach($this->getSortedConfigFactoryOverrides() as $override) { + $cache_key = $cache_key . ':' . $override->getCacheSuffix(); + } + } + else { + $cache_key = $name . ':raw'; } return $cache_key; } @@ -298,74 +281,11 @@ public function clearStaticCache() { /** * {@inheritdoc} */ - public function setLanguage(Language $language = NULL) { - $this->language = $language; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setLanguageFromDefault(LanguageDefault $language_default) { - $this->language = $language_default->get(); - return $this; - } - - /** - * {@inheritdoc} - */ - public function getLanguage() { - return $this->language; - } - - /** - * {@inheritdoc} - */ - public function getLanguageConfigNames(array $names) { - $language_names = array(); - if (isset($this->language)) { - foreach ($names as $name) { - if ($language_name = $this->getLanguageConfigName($this->language->id, $name)) { - $language_names[$name] = $language_name; - } - } - } - return $language_names; - } - - /** - * {@inheritdoc} - */ - public function getLanguageConfigName($langcode, $name) { - if (strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0) { - return FALSE; - } - return static::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.' . $name; - } - - /** - * {@inheritdoc} - */ public function listAll($prefix = '') { return $this->storage->listAll($prefix); } /** - * 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); - } - - /** * Removes stale static cache entries when configuration is saved. * * @param ConfigCrudEvent $event @@ -392,4 +312,30 @@ static function getSubscribedEvents() { return $events; } + /** + * {@inheritdoc} + */ + public function addOverride(ConfigFactoryOverrideInterface $config_factory_override, $priority) { + $this->configFactoryOverrides[$priority][] = $config_factory_override; + // Force the overrides to be re-sorted. + $this->sortedConfigFactoryOverrides = NULL; + } + + /** + * {@inheritdoc} + */ + public function getSortedConfigFactoryOverrides() { + if (!isset($this->sortedConfigFactoryOverrides)) { + // Sort the negotiators according to priority. + krsort($this->configFactoryOverrides); + // Merge nested negotiators from $this->configFactoryOverrides into + // $this->sortedConfigFactoryOverrides. + $this->sortedConfigFactoryOverrides = array(); + foreach ($this->configFactoryOverrides as $overrides) { + $this->sortedConfigFactoryOverrides = array_merge($this->sortedConfigFactoryOverrides, $overrides); + } + } + return $this->sortedConfigFactoryOverrides; + } + } diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php index 1969e82..ea60d67 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php +++ b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php @@ -7,20 +7,12 @@ namespace Drupal\Core\Config; -use Drupal\Core\Language\Language; -use Drupal\Core\Language\LanguageDefault; - /** * Defines the interface for a configuration object factory. */ interface ConfigFactoryInterface { /** - * Prefix for all language configuration files. - */ - const LANGUAGE_CONFIG_PREFIX = 'language.config'; - - /** * Sets the override state. * * @param bool $state @@ -117,78 +109,35 @@ public function getCacheKeys($name); public function clearStaticCache(); /** - * Sets the language to be used in configuration overrides. - * - * @param \Drupal\Core\Language\Language $language - * The language object to be set on the config factory. Used to override - * configuration by language. - * - * @return $this - */ - public function setLanguage(Language $language = NULL); - - /** - * Sets the language for configuration overrides using the default language. - * - * @param \Drupal\Core\Language\LanguageDefault $language_default - * The default language service. This sets the initial language on the - * config factory to the site's default. The language can be used to - * override configuration data if language overrides are available. - * - * @return $this - */ - public function setLanguageFromDefault(LanguageDefault $language_default); - - /** - * Gets the language Used to override configuration. - * - * @return \Drupal\Core\Language\Language - */ - public function getLanguage(); - - /** - * Gets configuration names for this language. + * Gets configuration object names starting with a given prefix. * - * It will be the same name with a prefix depending on language code: - * language.config.LANGCODE.NAME + * @see \Drupal\Core\Config\StorageInterface::listAll() * - * @param array $names - * A list of configuration object names. + * @param string $prefix + * (optional) The prefix to search for. If omitted, all configuration object + * names that exist are returned. * * @return array - * The localized config names, keyed by configuration object name. + * An array containing matching configuration object names. */ - public function getLanguageConfigNames(array $names); + public function listAll($prefix = ''); /** - * Gets configuration name for the provided language. - * - * 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 configuration object. + * Adds config factory override service. * - * @return bool|string - * The configuration name for configuration object providing overrides. - * Returns false if the name already starts with the language config prefix. + * @param \Drupal\Core\Config\ConfigFactoryOverrideInterface $config_factory_override + * The config factory to add. + * @param int $priority + * Priority of the config factory override. */ - public function getLanguageConfigName($langcode, $name); + public function addOverride(ConfigFactoryOverrideInterface $config_factory_override, $priority); /** - * Gets configuration object names starting with a given prefix. - * - * @see \Drupal\Core\Config\StorageInterface::listAll() - * - * @param string $prefix - * (optional) The prefix to search for. If omitted, all configuration object - * names that exist are returned. + * Returns the sorted array of config factory override objects. * - * @return array - * An array containing matching configuration object names. + * @return array|\Drupal\Core\Config\ConfigFactoryOverrideInterface[] + * An array of config factory override objects. */ - public function listAll($prefix = ''); + public function getSortedConfigFactoryOverrides(); } diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php new file mode 100644 index 0000000..75298b3 --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php @@ -0,0 +1,52 @@ +getDefinition('config.factory'); + foreach ($container->findTaggedServiceIds('config.factory.override') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $manager->addMethodCall('addOverride', array(new Reference($id), $priority)); + } + } + +} diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php index b91964e..27602a3 100644 --- a/core/lib/Drupal/Core/Config/ConfigImporter.php +++ b/core/lib/Drupal/Core/Config/ConfigImporter.php @@ -264,7 +264,7 @@ protected function process($op, $name) { * The name of the configuration to process. */ protected function importConfig($op, $name) { - $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager); + $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->typedConfigManager, $this->eventDispatcher); if ($op == 'delete') { $config->delete(); } @@ -301,13 +301,13 @@ protected function importInvokeOwner($op, $name) { // Validate the configuration object name before importing it. // Config::validateName($name); if ($entity_type = $this->configManager->getEntityTypeIdByName($name)) { - $old_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager); + $old_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->typedConfigManager, $this->eventDispatcher); if ($old_data = $this->storageComparer->getTargetStorage()->read($name)) { $old_config->initWithData($old_data); } $data = $this->storageComparer->getSourceStorage()->read($name); - $new_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager); + $new_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->typedConfigManager, $this->eventDispatcher); if ($data !== FALSE) { $new_config->setData($data); } diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php index 2bb06b3..2f09553 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -72,14 +72,14 @@ public function __construct(ConfigFactoryInterface $config_factory, StorageInter /** * {@inheritdoc} */ - public function installDefaultConfig($type, $name) { + public function installDefaultConfig($type, $extension_name) { // Get all default configuration owned by this extension. $source_storage = new ExtensionInstallStorage($this->activeStorage); - $config_to_install = $source_storage->listAll($name . '.'); + $config_to_install = $source_storage->listAll($extension_name . '.'); // Work out if this extension provides default configuration for any other // enabled extensions. - $config_dir = drupal_get_path($type, $name) . '/config'; + $config_dir = drupal_get_path($type, $extension_name) . '/config'; if (is_dir($config_dir)) { if (is_dir($config_dir . '/schema')) { // Refresh the schema cache if installing default configuration and the @@ -87,8 +87,8 @@ public function installDefaultConfig($type, $name) { $this->typedConfig->clearCachedDefinitions(); } $default_storage = new FileStorage($config_dir); - $other_module_config = array_filter($default_storage->listAll(), function ($value) use ($name) { - return !preg_match('/^' . $name . '\./', $value); + $other_module_config = array_filter($default_storage->listAll(), function ($value) use ($extension_name) { + return !preg_match('/^' . $extension_name . '\./', $value); }); // Read enabled extensions directly from configuration to avoid circular @@ -113,7 +113,7 @@ public function installDefaultConfig($type, $name) { continue; } - $new_config = new Config($name, $this->activeStorage, $this->eventDispatcher, $this->typedConfig); + $new_config = new Config($name, $this->activeStorage, $this->typedConfig, $this->eventDispatcher); $data = $source_storage->read($name); if ($data !== FALSE) { $new_config->setData($data); @@ -131,6 +131,11 @@ public function installDefaultConfig($type, $name) { } $this->configFactory->setOverrideState($old_state); } + + // Allow configFactory overrides to respond to installation. + foreach ($this->configFactory->getSortedConfigFactoryOverrides() as $config_override) { + $config_override->install($type, $extension_name); + } } } diff --git a/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php b/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php index 927c610..cf5cac8 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php +++ b/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php @@ -30,11 +30,11 @@ * * @param string $type * The extension type; e.g., 'module' or 'theme'. - * @param string $name + * @param string $extension_name * The name of the module or theme to install default configuration for. * * @see \Drupal\Core\Config\ExtensionInstallStorage */ - public function installDefaultConfig($type, $name); + public function installDefaultConfig($type, $extension_name); } diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php index 65a7846..415b105 100644 --- a/core/lib/Drupal/Core/Config/ConfigManager.php +++ b/core/lib/Drupal/Core/Config/ConfigManager.php @@ -128,6 +128,11 @@ function uninstall($type, $name) { foreach ($config_names as $config_name) { $this->configFactory->get($config_name)->delete(); } + // Allow configFactory overrides to respond to uninstallation. + foreach ($this->configFactory->getSortedConfigFactoryOverrides() as $config_override) { + $config_override->uninstall($type, $name); + } + $schema_dir = drupal_get_path($type, $name) . '/config/schema'; if (is_dir($schema_dir)) { // Refresh the schema cache if uninstalling an extension that provides diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index 2df9fbd..b8d9ed2 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -241,4 +241,15 @@ public function deleteAll($prefix = '') { return $success; } + + /** + * Sets rhe filesystem path for configuration objects. + * + * @param string $directory + * The filesystem path for configuration objects. + */ + public function setDirectory($directory) { + $this->directory = $directory; + } + } diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index d99ae28..571e4a4 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -8,6 +8,7 @@ namespace Drupal\Core; use Drupal\Core\Cache\ListCacheBinsPass; +use Drupal\Core\Config\ConfigFactoryOverridePass; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; @@ -75,6 +76,9 @@ public function register(ContainerBuilder $container) { // Add the compiler pass that will process the tagged theme negotiator // service. $container->addCompilerPass(new ThemeNegotiatorPass()); + // Add the compiler pass that will process the tagged config factory + // override services. + $container->addCompilerPass(new ConfigFactoryOverridePass()); // Add the compiler pass that lets service providers modify existing // service definitions. $container->addCompilerPass(new ModifyServiceDefinitionsPass()); diff --git a/core/lib/Drupal/Core/Datetime/Date.php b/core/lib/Drupal/Core/Datetime/Date.php index 5c2b92b..155ddd2 100644 --- a/core/lib/Drupal/Core/Datetime/Date.php +++ b/core/lib/Drupal/Core/Datetime/Date.php @@ -215,11 +215,14 @@ protected function t($string, array $args = array(), array $options = array()) { */ protected function dateFormat($format, $langcode) { if (!isset($this->dateFormats[$format][$langcode])) { - // Enter a language specific context so the right date format is loaded. - $original_language = $this->configFactory->getLanguage(); - $this->configFactory->setLanguage(new Language(array('id' => $langcode))); + if ($this->languageManager->isConfigurable()) { + $original_language = $this->languageManager->getConfigOverrideLanguage(); + $this->languageManager->setConfigOverrideLanguage(new Language(array('id' => $langcode))); + } $this->dateFormats[$format][$langcode] = $this->dateFormatStorage->load($format); - $this->configFactory->setLanguage($original_language); + if ($this->languageManager->isConfigurable()) { + $this->languageManager->setConfigOverrideLanguage($original_language); + } } return $this->dateFormats[$format][$langcode]; } diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php index 6ddf673..9f1ceeb 100644 --- a/core/lib/Drupal/Core/Language/LanguageManager.php +++ b/core/lib/Drupal/Core/Language/LanguageManager.php @@ -329,4 +329,11 @@ public static function getStandardLanguageList() { ); } + /** + * {@inheritdoc} + */ + public function isConfigurable() { + return FALSE; + } + } diff --git a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php index 16c7c01..656fc1f 100644 --- a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php +++ b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php @@ -168,4 +168,12 @@ public function getFallbackCandidates($langcode = NULL, array $context = array() */ function getLanguageSwitchLinks($type, $path); + /** + * Determines if thr language manager is configurable or not. + * + * @return bool + * TRUE if the LanguageManager is configurable, FALSE if not. + */ + public function isConfigurable(); + } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php index 27e8845..48c8727 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php @@ -37,7 +37,7 @@ public static function getInfo() { function testConfigEvents() { $name = 'config_events_test.test'; - $config = new Config($name, \Drupal::service('config.storage'), \Drupal::service('event_dispatcher'), \Drupal::service('config.typed')); + $config = new Config($name, \Drupal::service('config.storage'), \Drupal::service('config.typed'), \Drupal::service('event_dispatcher')); $config->set('key', 'initial'); \Drupal::state()->get('config_events_test.event', FALSE); $this->assertIdentical(\Drupal::state()->get('config_events_test.event', array()), array(), 'No events fired by creating a new configuration object'); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php similarity index 60% rename from core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php rename to core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php index 12ff3cd..9d2655a 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\config\Tests\ConfigLanguageOverride. + * Contains \Drupal\config\Tests\ConfigLanguageOverrideTest. */ namespace Drupal\config\Tests; @@ -13,14 +13,14 @@ /** * Tests language config override. */ -class ConfigLanguageOverride extends DrupalUnitTestBase { +class ConfigLanguageOverrideTest extends DrupalUnitTestBase { /** * Modules to enable. * * @var array */ - public static $modules = array('config_test', 'user', 'language', 'system', 'field'); + public static $modules = array('user', 'language', 'config_test', 'system', 'field'); public static function getInfo() { return array( @@ -39,16 +39,10 @@ public function setUp() { * Tests locale override based on language. */ function testConfigLanguageOverride() { - // The default configuration factory does not have the default language - // injected unless the Language module is enabled. - $config = \Drupal::config('config_test.system'); - $this->assertIdentical($config->get('foo'), 'bar'); - - // \Drupal\language\LanguageServiceProvider::alter() calls - // \Drupal\Core\Config\ConfigFactory::setLanguageFromDefault() to set the - // language when the Language module is enabled. This test ensures that + // The language module implements a config factory override object that + // overrides configuration when the Language module is enabled. This test ensures that // English overrides work. - \Drupal::configFactory()->setLanguageFromDefault(\Drupal::service('language.default')); + \Drupal::languageManager()->setConfigOverrideLanguage(language_load('en')); $config = \Drupal::config('config_test.system'); $this->assertIdentical($config->get('foo'), 'en bar'); @@ -65,20 +59,20 @@ function testConfigLanguageOverride() { 'id' => 'de', ))); - \Drupal::configFactory()->setLanguage(language_load('fr')); + \Drupal::languageManager()->setConfigOverrideLanguage(language_load('fr')); $config = \Drupal::config('config_test.system'); $this->assertIdentical($config->get('foo'), 'fr bar'); - \Drupal::configFactory()->setLanguage(language_load('de')); + \Drupal::languageManager()->setConfigOverrideLanguage(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'); + \Drupal::languageManager() + ->config('config_test.new', language_load('de')) + ->set('language', 'override')->save(); $config = \Drupal::config('config_test.new'); $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new'); $this->assertIdentical($config->get('language'), 'override'); @@ -87,11 +81,6 @@ function testConfigLanguageOverride() { $config = \Drupal::config('config_test.new'); $this->assertIdentical($config->get('language'), NULL); \Drupal::configFactory()->setOverrideState($old_state); - - // 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 --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php index 3ffb54f..01cda65 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php @@ -45,10 +45,13 @@ function testSiteNameTranslation() { 'direction' => '0', ); $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language')); - + \Drupal::languageManager()->reset(); // Save an override for the XX language. - $config_name = \Drupal::configFactory()->getLanguageConfigName('xx', 'system.site'); - \Drupal::config($config_name)->set('name', 'XX site name')->save(); + $language = language_load('xx'); + \Drupal::languageManager() + ->config('system.site', $language) + ->set('name', 'XX site name') + ->save(); $this->drupalLogout(); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php index 49482f9..112eeb3 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php @@ -15,7 +15,7 @@ */ class ConfigOverridesPriorityTest extends DrupalUnitTestBase { - public static $modules = array('system', 'config', 'config_override'); + public static $modules = array('system', 'config', 'config_override', 'language'); public static function getInfo() { return array( @@ -59,10 +59,9 @@ public function testOverridePriorities() { 'name' => 'French', 'id' => 'fr', )); - $config_factory->setLanguage($language); - $language_config_name = $config_factory->getLanguageConfigName($language->id, 'system.site'); - $config_factory - ->get($language_config_name) + \Drupal::languageManager()->setConfigOverrideLanguage($language); + \Drupal::languageManager() + ->config('system.site', $language) ->set('name', $language_overridden_name) ->set('mail', $language_overridden_mail) ->save(); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php index 62341ee..aed67af 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php @@ -21,7 +21,7 @@ class ConfigSchemaTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'locale', 'field', 'image', 'config_test'); + public static $modules = array('system', 'language', ',locale', 'field', 'image', 'config_test'); public static function getInfo() { return array( diff --git a/core/modules/config/tests/config_override/config_override.services.yml b/core/modules/config/tests/config_override/config_override.services.yml index 586ce49..5272a84 100644 --- a/core/modules/config/tests/config_override/config_override.services.yml +++ b/core/modules/config/tests/config_override/config_override.services.yml @@ -1,9 +1,9 @@ services: - config_override_config_subscriber: - class: Drupal\config_override\EventSubscriber\ConfigModuleOverrideSubscriber + config_override.overrider: + class: Drupal\config_override\ConfigOverrider tags: - - { name: event_subscriber } - config_override_low_priority_config_subscriber: - class: Drupal\config_override\EventSubscriber\ConfigModuleLowPriorityOverrideSubscriber + - { name: config.factory.override} + config_override.low_priority_overrider: + class: Drupal\config_override\ConfigOverriderLowPriority tags: - - { name: event_subscriber } + - { name: config.factory.override, priority: -100 } diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverrider.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverrider.php new file mode 100644 index 0000000..d82ed2e --- /dev/null +++ b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverrider.php @@ -0,0 +1,56 @@ + array('name' => 'ZOMG overridden site name')); + } + if (in_array('config_override.new', $names)) { + $overrides = $overrides + array('config_override.new' => array('module' => 'override')); + } + } + return $overrides; + } + + /** + * {@inheritdoc} + */ + public function getCacheSuffix() { + return 'ConfigOverrider'; + } + + /** + * {@inheritdoc} + */ + public function install($type, $name) { + } + + /** + * {@inheritdoc} + */ + public function uninstall($type, $name) { + } + +} + diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverriderLowPriority.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverriderLowPriority.php new file mode 100644 index 0000000..53a30e7 --- /dev/null +++ b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverriderLowPriority.php @@ -0,0 +1,57 @@ + + array( + // This override should apply because it is not overridden by the + // higher priority listener. + 'name' => 'Should not apply because of higher priority listener', + 'slogan' => 'Yay for overrides!', + ) + ); + } + } + return $overrides; + } + + /** + * {@inheritdoc} + */ + public function getCacheSuffix() { + return 'ConfigOverriderLowPriority'; + } + + /** + * {@inheritdoc} + */ + public function install($type, $name) { + } + + /** + * {@inheritdoc} + */ + public function uninstall($type, $name) { + } + +} + diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleLowPriorityOverrideSubscriber.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleLowPriorityOverrideSubscriber.php deleted file mode 100644 index fd7e26c..0000000 --- a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleLowPriorityOverrideSubscriber.php +++ /dev/null @@ -1,44 +0,0 @@ -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[ConfigEvents::MODULE_OVERRIDES][] = array('onConfigModuleOverride', 35); - return $events; - } -} - diff --git a/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 deleted file mode 100644 index e168111..0000000 --- a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php +++ /dev/null @@ -1,42 +0,0 @@ -getNames(); - 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')); - } - } - } - - /** - * Registers the methods in this class that should be listeners. - * - * @return array - * An array of event listener definitions. - */ - static function getSubscribedEvents() { - $events[ConfigEvents::MODULE_OVERRIDES][] = array('onConfigModuleOverride', 40); - return $events; - } -} - diff --git a/core/modules/config/tests/config_test/config/language.config.de.config_test.system.yml b/core/modules/config/tests/config_test/config/language/de/config_test.system.yml similarity index 100% rename from core/modules/config/tests/config_test/config/language.config.de.config_test.system.yml rename to core/modules/config/tests/config_test/config/language/de/config_test.system.yml diff --git a/core/modules/config/tests/config_test/config/language.config.en.config_test.system.yml b/core/modules/config/tests/config_test/config/language/en/config_test.system.yml similarity index 100% rename from core/modules/config/tests/config_test/config/language.config.en.config_test.system.yml rename to core/modules/config/tests/config_test/config/language/en/config_test.system.yml diff --git a/core/modules/config/tests/config_test/config/language.config.fr.config_test.system.yml b/core/modules/config/tests/config_test/config/language/fr/config_test.system.yml similarity index 100% rename from core/modules/config/tests/config_test/config/language.config.fr.config_test.system.yml rename to core/modules/config/tests/config_test/config/language/fr/config_test.system.yml diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php index 319e168..9a894d6 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php @@ -9,10 +9,9 @@ use Drupal\config_translation\ConfigMapperManagerInterface; use Drupal\Core\Cache\Cache; -use Drupal\Core\Config\StorageInterface; -use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\ConfirmFormBase; +use Drupal\language\Config\LanguageStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -23,9 +22,9 @@ class ConfigTranslationDeleteForm extends ConfirmFormBase { /** - * The configuration storage. + * The language override configuration storage. * - * @var \Drupal\Core\Config\StorageInterface $config_storage + * @var \Drupal\language\Config\LanguageStorageInterface $config_storage */ protected $configStorage; @@ -60,20 +59,17 @@ class ConfigTranslationDeleteForm extends ConfirmFormBase { /** * Constructs a ConfigTranslationDeleteForm. * - * @param \Drupal\Core\Config\StorageInterface $config_storage - * The configuration storage. + * @param \Drupal\language\Config\LanguageStorageInterface $config_storage + * The language override configuration storage. * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager * The configuration mapper manager. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The configuration factory. */ - public function __construct(StorageInterface $config_storage, ConfigMapperManagerInterface $config_mapper_manager, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) { + public function __construct(LanguageStorageInterface $config_storage, ConfigMapperManagerInterface $config_mapper_manager, ModuleHandlerInterface $module_handler) { $this->configStorage = $config_storage; $this->configMapperManager = $config_mapper_manager; $this->moduleHandler = $module_handler; - $this->configFactory = $config_factory; } /** @@ -81,10 +77,9 @@ public function __construct(StorageInterface $config_storage, ConfigMapperManage */ public static function create(ContainerInterface $container) { return new static( - $container->get('config.storage'), + $container->get('language.config_storage'), $container->get('plugin.manager.config_translation.mapper'), - $container->get('module_handler'), - $container->get('config.factory') + $container->get('module_handler') ); } @@ -141,9 +136,9 @@ public function buildForm(array $form, array &$form_state, Request $request = NU * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { + $this->configStorage->setLangcode($this->language->id); foreach ($this->mapper->getConfigNames() as $name) { - $config_name = $this->configFactory->getLanguageConfigName($this->language->id, $name); - $this->configStorage->delete($config_name); + $this->configStorage->delete($name); } // Flush all persistent caches. diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php index 22e6783..8726425 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php @@ -16,6 +16,7 @@ use Drupal\Core\Form\BaseFormIdInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Language\Language; +use Drupal\language\ConfigurableLanguageManagerInterface; use Drupal\locale\StringStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -62,6 +63,13 @@ protected $mapper; /** + * The lanugage manager. + * + * @var \Drupal\language\ConfigurableLanguageManagerInterface + */ + protected $languageManager; + + /** * The language of the configuration translation. * * @var \Drupal\Core\Language\Language @@ -96,12 +104,13 @@ * @param \Drupal\Core\Config\ConfigFactoryInterface * The config factory. */ - public function __construct(TypedConfigManager $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, StringStorageInterface $locale_storage, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) { + public function __construct(TypedConfigManager $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, StringStorageInterface $locale_storage, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, ConfigurableLanguageManagerInterface $language_manager) { $this->typedConfigManager = $typed_config_manager; $this->configMapperManager = $config_mapper_manager; $this->localeStorage = $locale_storage; $this->moduleHandler = $module_handler; $this->configFactory = $config_factory; + $this->languageManager = $language_manager; } /** @@ -113,7 +122,8 @@ public static function create(ContainerInterface $container) { $container->get('plugin.manager.config_translation.mapper'), $container->get('locale.storage'), $container->get('module_handler'), - $container->get('config.factory') + $container->get('config.factory'), + $container->get('language_manager') ); } @@ -172,8 +182,8 @@ public function buildForm(array $form, array &$form_state, Request $request = NU $this->configFactory->setOverrideState($old_state); // Set the translation target language on the configuration factory. - $original_language = $this->configFactory->getLanguage(); - $this->configFactory->setLanguage($this->language); + $original_language = $this->languageManager->getConfigOverrideLanguage(); + $this->languageManager->setConfigOverrideLanguage($this->language); // Add some information to the form state for easier form altering. $form_state['config_translation_mapper'] = $this->mapper; @@ -199,7 +209,7 @@ public function buildForm(array $form, array &$form_state, Request $request = NU ); // Set the configuration language back. - $this->configFactory->setLanguage($original_language); + $this->languageManager->setConfigOverrideLanguage($original_language); return $form; } @@ -217,8 +227,7 @@ public function submitForm(array &$form, array &$form_state) { foreach ($this->mapper->getConfigNames() as $name) { // Set configuration values based on form submission and source values. $base_config = $this->config($name); - $translation_config_name = $this->configFactory->getLanguageConfigName($this->language->id, $name); - $translation_config = $this->config($translation_config_name); + $translation_config = $this->languageManager->config($name, $this->language); $locations = $this->localeStorage->getLocations(array('type' => 'configuration', 'name' => $name)); $this->setConfig($this->language, $base_config, $translation_config, $form_values[$name], !empty($locations)); diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php index ed4b1e2..1997925 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php @@ -177,16 +177,14 @@ public function testSourceValueDuplicateSave() { $this->drupalPostForm("$translation_base_url/fr/add", $edit, t('Save translation')); // Read overridden file from active config. - $file_storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); - $language_config_name = \Drupal::configFactory()->getLanguageConfigName('fr', 'system.site'); - $config_parsed = $file_storage->read($language_config_name); + $config = \Drupal::languageManager()->config('system.site', language_load('fr')); // Expect both name and slogan in language specific file. $expected = array( 'name' => 'FR ' . $site_name, 'slogan' => 'FR ' . $site_slogan, ); - $this->assertEqual($expected, $config_parsed); + $this->assertEqual($expected, $config->get()); // Case 2: Update new value for site slogan and default value for site name. $this->drupalGet("$translation_base_url/fr/edit"); @@ -200,11 +198,11 @@ 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($language_config_name); + $config = \Drupal::languageManager()->config('system.site', language_load('fr')); // Expect only slogan in language specific file. $expected = array('slogan' => 'FR ' . $site_slogan); - $this->assertEqual($expected, $config_parsed); + $this->assertEqual($expected, $config->get()); // Case 3: Keep default value for site name and slogan. $this->drupalGet("$translation_base_url/fr/edit"); @@ -214,10 +212,10 @@ public function testSourceValueDuplicateSave() { 'config_names[system.site][slogan][translation]' => $site_slogan, ); $this->drupalPostForm(NULL, $edit, t('Save translation')); - $config_parsed = $file_storage->read($language_config_name); + $config = \Drupal::languageManager()->config('system.site', language_load('fr')); // Expect no language specific file. - $this->assertFalse($config_parsed); + $this->assertTrue($config->isNew()); // Check configuration page with translator user. Should have no access. $this->drupalLogout(); @@ -240,8 +238,6 @@ public function testSourceValueDuplicateSave() { public function testContactConfigEntityTranslation() { $this->drupalLogin($this->admin_user); - $file_storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); - $this->drupalGet('admin/structure/contact'); // Check for default contact form configuration entity from Contact module. @@ -285,13 +281,12 @@ public function testContactConfigEntityTranslation() { $this->drupalPostForm($translation_page_url, $edit, t('Save translation')); // Expect translated values in language specific file. - $language_config_name = \Drupal::configFactory()->getLanguageConfigName($langcode, 'contact.category.feedback'); - $config_parsed = $file_storage->read($language_config_name); + $config = \Drupal::languageManager()->config('contact.category.feedback', language_load($langcode)); $expected = array( 'label' => 'Website feedback - ' . $langcode, 'reply' => 'Thank you for your mail - ' . $langcode, ); - $this->assertEqual($expected, $config_parsed); + $this->assertEqual($expected, $config->get()); // Check for edit, delete links (and no 'add' link) for $langcode. $this->assertNoLinkByHref("$translation_base_url/$langcode/add"); @@ -349,9 +344,8 @@ public function testContactConfigEntityTranslation() { $this->assertNoLinkByHref("$translation_base_url/$langcode/delete"); // Expect no language specific file present anymore. - $language_config_name = \Drupal::configFactory()->getLanguageConfigName($langcode, 'contact.category.feedback'); - $config_parsed = $file_storage->read($language_config_name); - $this->assertFalse($config_parsed); + $config = \Drupal::languageManager()->config('contact.category.feedback', language_load($langcode)); + $this->assertTrue($config->isNew()); } // Check configuration page with translator user. Should have no access. @@ -417,13 +411,12 @@ public function testDateFormatTranslation() { $this->drupalPostForm($translation_page_url, $edit, t('Save translation')); // Get translation and check we've got the right value. - $language_config_name = \Drupal::configFactory()->getLanguageConfigName('fr', 'system.date_format.' . $id); - $config_parsed = $file_storage->read($language_config_name); + $config = \Drupal::languageManager()->config('system.date_format.' . $id, language_load('fr')); $expected = array( 'label' => $id . ' - FR', 'pattern' => array('php' => 'D'), ); - $this->assertEqual($expected, $config_parsed); + $this->assertEqual($expected, $config->get()); // Formatting the date 8 / 27 / 1985 @ 13:37 EST with pattern D should // display "Tue". diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml index 422644a..6aa9db7 100644 --- a/core/modules/language/language.services.yml +++ b/core/modules/language/language.services.yml @@ -11,3 +11,14 @@ services: class: Drupal\language\EventSubscriber\ConfigSubscriber tags: - { name: event_subscriber } + language.config_storage: + class: Drupal\language\Config\LanguageStorage + arguments: ['@cache.config'] + tags: + - { name: persist } + language.config_factory_override: + class: Drupal\language\Config\LanguageConfigOverride + arguments: ['@language.default', '@language.config_storage', '@config.typed'] + tags: + - { name: config.factory.override, priority: -254 } + - { name: persist } diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php new file mode 100644 index 0000000..58b261e --- /dev/null +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php @@ -0,0 +1,131 @@ +language = $language_default->get(); + $this->storage = $storage->setLangcode($this->language->id); + $this->typedConfig = $typed_config; + } + + /** + * {@inheritdoc} + */ + public function loadOverrides($names) { + return $this->storage->readMultiple($names); + } + + /** + * {@inheritdoc} + */ + public function getCacheSuffix() { + return $this->language->id; + } + + /** + * {@inheritdoc} + * + * @todo maybe this should be done somewhere else? + */ + public function install($type, $name) { + // Work out if this extension provides default language overrides. + $config_dir = drupal_get_path($type, $name) . '/config/language'; + if (is_dir($config_dir)) { + // List all the directories. + // \DirectoryIterator on Windows requires an absolute path. + $it = new \DirectoryIterator(realpath($config_dir)); + foreach ($it as $dir) { + if (!$dir->isDot() && $dir->isDir() ) { + $default_language_config = new FileStorage($dir->getPathname()); + $this->storage->setLangcode($dir->getFilename()); + foreach ($default_language_config->listAll() as $config_name) { + $data = $default_language_config->read($config_name); + $config = new Config($config_name, $this->storage, $this->typedConfig); + $config->setData($data)->save(); + } + } + } + } + } + + /** + * {@inheritdoc} + * + * @todo maybe this should be done somewhere else? + */ + public function uninstall($type, $name) { + // Can not use ConfigurableLanguageManager::getLanguages() since that would + // create a circular dependency. + $language_directory = config_get_config_directory() .'/language'; + if (is_dir(($language_directory))) { + $it = new \DirectoryIterator(realpath($language_directory)); + foreach ($it as $dir) { + if (!$dir->isDot() && $dir->isDir() ) { + $this->storage->setLangcode($dir->getFilename()); + $config_names = $this->storage->listAll($name . '.'); + foreach ($config_names as $config_name) { + $config = new Config($config_name, $this->storage, $this->typedConfig); + $config->delete(); + } + } + } + } + } + + /** + * {@inheritdoc} + */ + public function getLanguage() { + return $this->language; + } + + /** + * {@inheritdoc} + */ + public function setLanguage(Language $language = NULL) { + $this->language = $language; + $this->storage->setLangcode($this->language->id); + return $this; + } + +} diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php new file mode 100644 index 0000000..63467e7 --- /dev/null +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php @@ -0,0 +1,34 @@ +cache = $cache; + } + + /** + * Gets the override configuration directory for a langcode. + * + * @param string $langcode + * The language langcode to get the directory for. + * + * @return string + * The directory where the language override configuration is stored. + */ + protected function getDirectory($langcode) { + return config_get_config_directory(CONFIG_ACTIVE_DIRECTORY) .'/language/' . $langcode; + } + + /** + * {@inheritdoc} + */ + public function write($name, array $data) { + $this->ensureDirectory(); + return parent::write($name, $data); + } + + /** + * {@inheritdoc} + */ + public function delete($name) { + if ($this->hasDirectory()) { + return parent::delete($name); + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function listAll($prefix = '') { + if ($this->hasDirectory()) { + return parent::listAll($prefix); + } + return array(); + } + + /** + * Creates a directory if necessary. + */ + protected function ensureDirectory() { + if (!$this->hasDirectory()) { + drupal_mkdir($this->directory, NULL, TRUE); + $this->directoryExists = TRUE; + } + } + + /** + * {@inheritdoc} + */ + public function setLangcode($langcode) { + // Reset directory check. + $this->directoryExists = NULL; + $this->langcode = $langcode; + $this->directory = $this->getDirectory($langcode); + if (empty($this->storage)) { + $this->storage = new FileStorage($this->directory); + } + else { + $this->storage->setDirectory($this->directory); + } + return $this; + } + + /** + * {@inheritdoc} + */ + protected function getCacheKey($name) { + return 'language.' . $this->langcode . ':' . $name; + } + + /** + * {@inheritdoc} + */ + protected function getCacheKeys(array $names) { + foreach ($names as &$name) { + $name = $this->getCacheKey($name); + } + return $names; + } + + /** + * {@inheritdoc} + */ + protected function getNameFromCacheKey($key) { + // Remove everything before the semicolon. + return substr($key, strpos($key, ':') + 1); + } + + /** + * Discovers is the directory for the langcode exists. + * + * @return bool + * TRUE if the directory exists, FALSE if not. + */ + protected function hasDirectory() { + if (!isset($this->directoryExists)) { + $this->directoryExists = is_dir($this->directory); + } + return $this->directoryExists; + } + +} diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php new file mode 100644 index 0000000..d16bad1 --- /dev/null +++ b/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php @@ -0,0 +1,26 @@ +defaultLanguage = $default_language; $this->configFactory = $config_factory; $this->moduleHandler = $module_handler; + $this->configFactoryOverride = $config_override; + $this->configStorage = $config_storage; + $this->typedConfig = $typed_config; } /** @@ -372,4 +408,39 @@ public function getLanguageSwitchLinks($type, $path) { return $links; } + /** + * {@inheritdoc} + */ + public function setConfigOverrideLanguage(Language $language) { + $this->configFactoryOverride->setLanguage($language); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getConfigOverrideLanguage() { + return $this->configFactoryOverride->getLanguage(); + } + + /** + * {@inheritdoc} + */ + public function config($name, Language $language) { + $data = $this->configStorage->setLangcode($language->id)->read($name); + // This is not regular configuration do not use an event dispatcher. + $config = new Config($name, $this->configStorage, $this->typedConfig); + if (!empty($data)) { + $config->initWithData($data); + } + return $config; + } + + /** + * {@inheritdoc} + */ + public function isConfigurable() { + return TRUE; + } + } diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php index 02c8205..4fc9078 100644 --- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php +++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php @@ -17,6 +17,11 @@ interface ConfigurableLanguageManagerInterface extends LanguageManagerInterface { /** + * TRUE if the LanguageManager is configurable. Default implementation is FALSE. + */ + const CONFIGURABLE = TRUE; + + /** * Injects the request object. * * @param \Symfony\Component\HttpFoundation\Request @@ -78,4 +83,36 @@ public function saveLanguageTypesConfiguration(array $config); */ public function updateLockedLanguageWeights(); + /** + * Sets the configuration override language. + * + * @param \Drupal\Core\Language\Language $language + * The language to override configuration with. + * + * @return $this + * The configurable language manager. + */ + public function setConfigOverrideLanguage(Language $language); + + /** + * Gets the current configuration override language. + * + * @return \Drupal\Core\Language\Language $language + * The current configuration override language. + */ + public function getConfigOverrideLanguage(); + + /** + * Gets language override configuration object. + * + * @param $name + * The configuration object name. + * @param \Drupal\Core\Language\Language $language + * The language to get the configuration object for. + * + * @return \Drupal\Core\Config\Config + * The language override configuration object. + */ + public function config($name, Language $language); + } diff --git a/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php index 2d81206..8741057 100644 --- a/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php +++ b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php @@ -7,11 +7,10 @@ namespace Drupal\language\EventSubscriber; -use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\Translator\TranslatorInterface; use Drupal\language\ConfigurableLanguageManagerInterface; +use Drupal\language\Config\LanguageConfigOverride; use Drupal\language\LanguageNegotiatorInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; @@ -52,13 +51,6 @@ class LanguageRequestSubscriber implements EventSubscriberInterface { protected $currentUser; /** - * The configuration factory. - * - * @var \Drupal\Core\Config\ConfigFactoryInterface - */ - protected $configFactory; - - /** * Constructs a LanguageRequestSubscriber object. * * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager @@ -69,15 +61,12 @@ class LanguageRequestSubscriber implements EventSubscriberInterface { * The translation service. * @param \Drupal\Core\Session\AccountInterface $current_user * The current active user. - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The configuration factory. */ - public function __construct(ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, TranslatorInterface $translation, AccountInterface $current_user, ConfigFactoryInterface $config_factory) { + public function __construct(ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, TranslatorInterface $translation, AccountInterface $current_user) { $this->languageManager = $language_manager; $this->negotiator = $negotiator; $this->translation = $translation; $this->currentUser = $current_user; - $this->configFactory = $config_factory; } /** @@ -94,7 +83,7 @@ public function onKernelRequestLanguage(GetResponseEvent $event) { if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) { $this->languageManager->setNegotiator($this->negotiator); $this->languageManager->setRequest($request); - $this->configFactory->setLanguage($this->languageManager->getCurrentLanguage()); + $this->languageManager->setConfigOverrideLanguage($this->languageManager->getCurrentLanguage()); } // After the language manager has initialized, set the default langcode // for the string translations. diff --git a/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php index 8c11eca..4b7aac4 100644 --- a/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php +++ b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php @@ -31,8 +31,7 @@ public function register(ContainerBuilder $container) { ->addArgument(new Reference('language_manager')) ->addArgument(new Reference('language_negotiator')) ->addArgument(new Reference('string_translation')) - ->addArgument(new Reference('current_user')) - ->addArgument(new Reference('config.factory')); + ->addArgument(new Reference('current_user')); $container->register('path_processor_language', 'Drupal\language\HttpKernel\PathProcessorLanguage') ->addTag('path_processor_inbound', array('priority' => 300)) @@ -52,14 +51,12 @@ public function alter(ContainerBuilder $container) { $definition = $container->getDefinition('language_manager'); $definition->setClass('Drupal\language\ConfigurableLanguageManager') ->addArgument(new Reference('config.factory')) - ->addArgument(new Reference('module_handler')); + ->addArgument(new Reference('module_handler')) + ->addArgument(new Reference('language.config_factory_override')) + ->addArgument(new Reference('language.config_storage')) + ->addArgument(new Reference('config.typed')); if ($default_language_values = $this->getDefaultLanguageValues()) { $container->setParameter('language.default_values', $default_language_values); - // Ensure that configuration can be localised if the site is monolingual - // but the Language module is enabled. This is the case for monolingual - // sites not in English. - $definition = $container->getDefinition('config.factory'); - $definition->addMethodCall('setLanguageFromDefault', array(new Reference('language.default'))); } } diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php index 353fcc6..bb9d197 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php @@ -12,6 +12,7 @@ use Drupal\Core\Config\TypedConfigManager; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\language\Config\LanguageStorageInterface; /** * Manages localized configuration type plugins. @@ -45,6 +46,13 @@ class LocaleConfigManager extends TypedConfigManager { protected $configFactory; /** + * The language configuration storage. + * + * @var \Drupal\language\Config\LanguageStorageInterface + */ + protected $languageStorage; + + /** * Creates a new typed configuration manager. * * @param \Drupal\Core\Config\StorageInterface $configStorage @@ -60,13 +68,16 @@ class LocaleConfigManager extends TypedConfigManager { * The cache backend to use for caching the definitions. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The configuration factory + * @param \Drupal\language\Config\LanguageStorage + * The language configuration storage. */ - public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory) { + public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory, LanguageStorageInterface $language_storage) { // Note we use the install storage for the parent constructor. parent::__construct($configStorage, $schemaStorage, $cache); $this->installStorage = $installStorage; $this->localeStorage = $localeStorage; $this->configFactory = $config_factory; + $this->languageStorage = $language_storage; } /** @@ -133,8 +144,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 = $this->configFactory->getLanguageConfigName($langcode, $name); - $this->configStorage->write($locale_name, $data); + $this->languageStorage->setLangcode($langcode)->write($name, $data); } /** @@ -146,8 +156,7 @@ public function saveTranslationData($name, $langcode, array $data) { * Language code. */ public function deleteTranslationData($name, $langcode) { - $locale_name = $this->configFactory->getLanguageConfigName($langcode, $name); - $this->configStorage->delete($locale_name); + $this->languageStorage->setLangcode($langcode)->delete($name); } /** @@ -220,9 +229,9 @@ public function getStringNames(array $lids) { * Language code to delete. */ public function deleteLanguageTranslations($langcode) { - $locale_name = ConfigFactoryInterface::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.'; - foreach ($this->configStorage->listAll($locale_name) as $name) { - $this->configStorage->delete($name); + $this->languageStorage->setLangcode($langcode); + foreach ($this->languageStorage->listAll() as $name) { + $this->languageStorage->delete($name); } } @@ -305,8 +314,7 @@ public function translateString($name, $langcode, $source, $context) { * A boolean indicating if a language has configuration translations. */ public function hasTranslation($name, Language $language) { - $locale_name = $this->configFactory->getLanguageConfigName($language->id, $name); - $translation = $this->configStorage->read($locale_name); + $translation = $this->languageStorage->setLangcode($language->id)->read($name); return !empty($translation); } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php index 16fc30b..36e51a9 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php @@ -22,7 +22,7 @@ class LocaleConfigManagerTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('locale', 'locale_test'); + public static $modules = array('language', 'locale', 'locale_test'); /** * {@inheritdoc} @@ -39,30 +39,19 @@ public static function getInfo() { * Tests hasTranslation(). */ public function testHasTranslation() { + $this->installConfig(array('locale_test')); $locale_config_manager = new LocaleConfigManager( - // In contrast to the actual configuration we use the installer storage - // as the config storage. That way, we do not actually have to install - // the module and can extend DrupalUnitTestBase. - $this->container->get('config.storage.installer'), + $this->container->get('config.storage'), $this->container->get('config.storage.schema'), $this->container->get('config.storage.installer'), $this->container->get('locale.storage'), $this->container->get('cache.config'), - $this->container->get('config.factory') + $this->container->get('config.factory'), + $this->container->get('language.config_storage') ); $language = new Language(array('id' => 'de')); - // The installer storage throws an expcetion when requesting a non-existing - // file. - try { - $locale_config_manager->hasTranslation('locale_test.no_translation', $language); - } - catch (StorageException $exception) { - $result = FALSE; - } - $this->assertIdentical(FALSE, $result); - - $result = $locale_config_manager->hasTranslation('locale_test.translation', $language); - $this->assertIdentical(TRUE, $result); + $this->assertFalse($locale_config_manager->hasTranslation('locale_test.no_translation', $language), 'There is no translation for locale_test.no_translation configuration.'); + $this->assertTrue($locale_config_manager->hasTranslation('locale_test.translation', $language), 'There is a translation for locale_test.translation configuration.'); } } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php index f7c64bf..5594d25 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php @@ -171,15 +171,16 @@ function testConfigTranslation() { $this->assertEqual($property->getValue(), $image_style_label, 'Got the right translation for image style name after translation'); // Quick test to ensure translation file exists. - $language_config_name = \Drupal::configFactory()->getLanguageConfigName('xx', 'image.style.medium'); - $this->assertEqual(\Drupal::config($language_config_name)->get('label'), $image_style_label); + $config = \Drupal::languageManager()->config('image.style.medium', language_load('xx')); + $this->assertEqual($config->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($language_config_name)->get('label'), 'Translated configuration for image module removed.'); + $config = \Drupal::languageManager()->config('image.style.medium', language_load('xx')); + $this->assertFalse($config->get('label'), 'Translated configuration for image module removed.'); // Translate default category using the UI so configuration is refreshed. $category_label = $this->randomName(20); diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml index b5f4cf4..250e648 100644 --- a/core/modules/locale/locale.services.yml +++ b/core/modules/locale/locale.services.yml @@ -6,7 +6,7 @@ services: arguments: ['@entity.manager', '@config.factory'] locale.config.typed: class: Drupal\locale\LocaleConfigManager - arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory'] + arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory', '@language.config_storage'] locale.storage: class: Drupal\locale\StringDatabaseStorage arguments: ['@database'] diff --git a/core/modules/locale/tests/modules/locale_test/config/language.config.de.locale_test.translation.yml b/core/modules/locale/tests/modules/locale_test/config/language/de/locale_test.translation.yml similarity index 100% rename from core/modules/locale/tests/modules/locale_test/config/language.config.de.locale_test.translation.yml rename to core/modules/locale/tests/modules/locale_test/config/language/de/locale_test.translation.yml diff --git a/core/modules/tour/tests/tour_test/config/language.config.it.tour.tour.tour-test.yml b/core/modules/tour/tests/tour_test/config/language/it/tour.tour.tour-test.yml similarity index 100% rename from core/modules/tour/tests/tour_test/config/language.config.it.tour.tour.tour-test.yml rename to core/modules/tour/tests/tour_test/config/language/it/tour.tour.tour-test.yml diff --git a/core/modules/user/user.module b/core/modules/user/user.module index d07ebd4..612c20f 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -1383,10 +1383,12 @@ function user_mail($key, &$message, $params) { $langcode = $message['langcode']; $variables = array('user' => $params['account']); - $original_language = \Drupal::configFactory()->getLanguage(); - $language = language_load($params['account']->getPreferredLangcode()); - \Drupal::configFactory()->setLanguage($language); + $language_manager = \Drupal::languageManager(); + if ($language_manager->isConfigurable()) { + $original_language = $language_manager->getConfigOverrideLanguage(); + $language_manager->setConfigOverrideLanguage($language); + } $mail_config = \Drupal::config('user.mail'); // We do not sanitize the token replacement, since the output of this @@ -1395,7 +1397,10 @@ function user_mail($key, &$message, $params) { $message['subject'] .= $token_service->replace($mail_config->get($key . '.subject'), $variables, $token_options); $message['body'][] = $token_service->replace($mail_config->get($key . '.body'), $variables, $token_options); - \Drupal::configFactory()->setLanguage($original_language); + if ($language_manager->isConfigurable()) { + $language_manager->setConfigOverrideLanguage($original_language); + } + } /**