diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 81ecd11..2caf789 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -928,17 +928,17 @@ function theme_get_setting($setting_name, $theme = NULL) { } foreach ($theme_keys as $theme_key) { if (!empty($themes[$theme_key]->info['settings'])) { - $cache[$theme]->mergeData($themes[$theme_key]->info['settings']); + $cache[$theme]->merge($themes[$theme_key]->info['settings']); } } } // Get the global settings from configuration. - $cache[$theme]->mergeData(\Drupal::config('system.theme.global')->get()); + $cache[$theme]->merge(\Drupal::config('system.theme.global')->get()); if ($theme) { // Get the saved theme-specific settings from the configuration system. - $cache[$theme]->mergeData(\Drupal::config($theme . '.settings')->get()); + $cache[$theme]->merge(\Drupal::config($theme . '.settings')->get()); // If the theme does not support a particular feature, override the global // setting and set the value to NULL. diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php index c122260..5af3346 100644 --- a/core/lib/Drupal/Core/Config/CachedStorage.php +++ b/core/lib/Drupal/Core/Config/CachedStorage.php @@ -248,7 +248,7 @@ public function resetListCache() { * configuration object name is 250 characters this should never add more than * 5 characters to the cache key. * - * @see \Drupal\language\Config\LanguageStorage::getCacheKey() + * @see \Drupal\language\Config\LanguageOverrideStorage::getCacheKey() * * @param string $name * The configuration object name. diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index e864af2..15ec667 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -8,31 +8,12 @@ namespace Drupal\Core\Config; use Drupal\Component\Utility\NestedArray; -use Drupal\Component\Utility\String; -use Drupal\Core\Config\ConfigNameException; -use Drupal\Core\Config\Schema\SchemaIncompleteException; -use Drupal\Core\DependencyInjection\DependencySerialization; -use Drupal\Core\TypedData\PrimitiveInterface; -use Drupal\Core\TypedData\Type\FloatInterface; -use Drupal\Core\TypedData\Type\IntegerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Defines the default configuration object. */ -class Config extends DependencySerialization { - - /** - * The maximum length of a configuration object name. - * - * Many filesystems (including HFS, NTFS, and ext4) have a maximum file name - * length of 255 characters. To ensure that no configuration objects - * incompatible with this limitation are created, we enforce a maximum name - * length of 250 characters (leaving 5 characters for the file extension). - * - * @see http://en.wikipedia.org/wiki/Comparison_of_file_systems - */ - const MAX_NAME_LENGTH = 250; +class Config extends StorableConfigBase { /** * An event dispatcher instance to use for configuration events. @@ -49,27 +30,6 @@ class Config extends DependencySerialization { protected $name; /** - * Whether the configuration object is new or has been saved to the storage. - * - * @var bool - */ - protected $isNew = TRUE; - - /** - * The data of the configuration object. - * - * @var array - */ - protected $data = array(); - - /** - * The original data of the configuration object. - * - * @var array - */ - protected $originalData = array(); - - /** * The current runtime data. * * The configuration data from storage merged with module and settings @@ -87,25 +47,11 @@ class Config extends DependencySerialization { protected $moduleOverrides; /** - * The storage used to load and save this configuration object. + * The current settings overrides. * - * @var \Drupal\Core\Config\StorageInterface - */ - protected $storage; - - /** - * The config schema wrapper object for this configuration object. - * - * @var \Drupal\Core\Config\Schema\Element - */ - protected $schemaWrapper; - - /** - * The typed config manager. - * - * @var \Drupal\Core\Config\TypedConfigManager + * @var array */ - protected $typedConfigManager; + protected $settingsOverrides; /** * Constructs a configuration object. @@ -115,13 +61,12 @@ 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 \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, TypedConfigManager $typed_config, EventDispatcherInterface $event_dispatcher = NULL) { + public function __construct($name, StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManager $typed_config) { $this->name = $name; $this->storage = $storage; $this->eventDispatcher = $event_dispatcher; @@ -129,110 +74,19 @@ public function __construct($name, StorageInterface $storage, TypedConfigManager } /** - * Initializes a configuration object with pre-loaded data. - * - * @param array $data - * Array of loaded data for this configuration object. - * - * @return \Drupal\Core\Config\Config - * The configuration object. + * {@inheritdoc} */ public function initWithData(array $data) { $this->settingsOverrides = array(); $this->moduleOverrides = array(); $this->isNew = FALSE; - $this->replaceData($data); + $this->setData($data); $this->originalData = $this->data; return $this; } /** - * Returns the name of this configuration object. - * - * @return string - * The name of the configuration object. - */ - public function getName() { - return $this->name; - } - - /** - * Sets the name of this configuration object. - * - * @param string $name - * The name of the configuration object. - * - * @return \Drupal\Core\Config\Config - * The configuration object. - */ - public function setName($name) { - $this->name = $name; - return $this; - } - - /** - * Validates the configuration object name. - * - * @param string $name - * The name of the configuration object. - * - * @throws \Drupal\Core\Config\ConfigNameException - * - * @see Config::MAX_NAME_LENGTH - */ - public static function validateName($name) { - // The name must be namespaced by owner. - if (strpos($name, '.') === FALSE) { - throw new ConfigNameException(format_string('Missing namespace in Config object name @name.', array( - '@name' => $name, - ))); - } - // The name must be shorter than Config::MAX_NAME_LENGTH characters. - if (strlen($name) > self::MAX_NAME_LENGTH) { - throw new ConfigNameException(format_string('Config object name @name exceeds maximum allowed length of @length characters.', array( - '@name' => $name, - '@length' => self::MAX_NAME_LENGTH, - ))); - } - - // The name must not contain any of the following characters: - // : ? * < > " ' / \ - if (preg_match('/[:?*<>"\'\/\\\\]/', $name)) { - throw new ConfigNameException(format_string('Invalid character in Config object name @name.', array( - '@name' => $name, - ))); - } - } - - /** - * Returns whether this configuration object is new. - * - * @return bool - * TRUE if this configuration object does not exist in storage. - */ - public function isNew() { - return $this->isNew; - } - - /** - * Gets data from this configuration object. - * - * @param string $key - * A string that maps to a key within the configuration data. - * For instance in the following configuration array: - * @code - * array( - * 'foo' => array( - * 'bar' => 'baz', - * ), - * ); - * @endcode - * A key of 'foo.bar' would return the string 'baz'. However, a key of 'foo' - * would return array('bar' => 'baz'). - * If no key is specified, then the entire data array is returned. - * - * @return mixed - * The data that was requested. + * {@inheritdoc} */ public function get($key = '') { if (!isset($this->overriddenData)) { @@ -254,36 +108,11 @@ public function get($key = '') { } /** - * Replaces the data of this configuration object. - * - * @param array $data - * The new configuration data. - * - * @return \Drupal\Core\Config\Config - * The configuration object. + * {@inheritdoc} */ public function setData(array $data) { - $this->replaceData($data); - return $this; - } - - /** - * Replaces the data of this configuration object. - * - * This function is separate from setData() to avoid load() state tracking. - * A load() would destroy the replaced data (for example on import). Do not - * call set() when inside load(). - * - * @param array $data - * The new configuration data. - * - * @return \Drupal\Core\Config\Config - * The configuration object. - */ - protected function replaceData(array $data) { $this->data = $data; - $this->resetOverriddenData(); - return $this; + return $this->resetOverriddenData(); } /** @@ -356,56 +185,23 @@ protected function resetOverriddenData() { } /** - * Sets a value in this configuration object. - * - * @param string $key - * Identifier to store value in configuration. - * @param mixed $value - * Value to associate with identifier. - * - * @return \Drupal\Core\Config\Config - * The configuration object. + * {@inheritdoc} */ public function set($key, $value) { - // The dot/period is a reserved character; it may appear between keys, but - // not within keys. - $parts = explode('.', $key); - if (count($parts) == 1) { - $this->data[$key] = $value; - } - else { - NestedArray::setValue($this->data, $parts, $value); - } - $this->resetOverriddenData(); - return $this; + parent::set($key, $value); + return $this->resetOverriddenData(); } /** - * Unsets a value in this configuration object. - * - * @param string $key - * Name of the key whose value should be unset. - * - * @return \Drupal\Core\Config\Config - * The configuration object. + * {@inheritdoc} */ public function clear($key) { - $parts = explode('.', $key); - if (count($parts) == 1) { - unset($this->data[$key]); - } - else { - NestedArray::unsetValue($this->data, $parts); - } - $this->resetOverriddenData(); - return $this; + parent::clear($key); + return $this->resetOverriddenData(); } /** - * Saves the configuration object. - * - * @return \Drupal\Core\Config\Config - * The configuration object. + * {@inheritdoc} */ public function save() { // Validate the configuration object name before saving. @@ -423,18 +219,13 @@ public function save() { $this->storage->write($this->name, $this->data); $this->isNew = FALSE; - if (isset($this->eventDispatcher)) { - $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this)); - } + $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this)); $this->originalData = $this->data; return $this; } /** - * Deletes the configuration object. - * - * @return \Drupal\Core\Config\Config - * The configuration object. + * {@inheritdoc} */ public function delete() { // @todo Consider to remove the pruning of data for Config::delete(). @@ -442,119 +233,12 @@ public function delete() { $this->storage->delete($this->name); $this->isNew = TRUE; $this->resetOverriddenData(); - if (isset($this->eventDispatcher)) { - $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this)); - } + $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this)); $this->originalData = $this->data; return $this; } /** - * Retrieves the storage used to load and save this configuration object. - * - * @return \Drupal\Core\Config\StorageInterface - * The configuration storage object. - */ - public function getStorage() { - return $this->storage; - } - - /** - * Merges data into a configuration object. - * - * @param array $data_to_merge - * An array containing data to merge. - * - * @return \Drupal\Core\Config\Config - * The configuration object. - */ - public function merge(array $data_to_merge) { - // Preserve integer keys so that configuration keys are not changed. - $this->replaceData(NestedArray::mergeDeepArray(array($this->data, $data_to_merge), TRUE)); - return $this; - } - - /** - * Gets the schema wrapper for the whole configuration object. - * - * The schema wrapper is dependent on the configuration name and the whole - * data structure, so if the name or the data changes in any way, the wrapper - * should be reset. - * - * @return \Drupal\Core\Config\Schema\Element - */ - protected function getSchemaWrapper() { - if (!isset($this->schemaWrapper)) { - $definition = $this->typedConfigManager->getDefinition($this->name); - $this->schemaWrapper = $this->typedConfigManager->create($definition, $this->data); - } - return $this->schemaWrapper; - } - - /** - * Casts the value to correct data type using the configuration schema. - * - * @param string $key - * A string that maps to a key within the configuration data. - * @param string $value - * Value to associate with the key. - * - * @return mixed - * The value cast to the type indicated in the schema. - * - * @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException - * Exception on unsupported/undefined data type deducted. - */ - protected function castValue($key, $value) { - if ($value === NULL) { - $value = NULL; - } - elseif (is_scalar($value)) { - try { - $element = $this->getSchemaWrapper()->get($key); - if ($element instanceof PrimitiveInterface) { - // Special handling for integers and floats since the configuration - // system is primarily concerned with saving values from the Form API - // we have to special case the meaning of an empty string for numeric - // types. In PHP this would be casted to a 0 but for the purposes of - // configuration we need to treat this as a NULL. - if ($value === '' && ($element instanceof IntegerInterface || $element instanceof FloatInterface)) { - $value = NULL; - } - else { - $value = $element->getCastedValue(); - } - } - else { - // Config only supports primitive data types. If the config schema - // does define a type $element will be an instance of - // \Drupal\Core\Config\Schema\Property. Convert it to string since it - // is the safest possible type. - $value = $element->getString(); - } - } - catch (SchemaIncompleteException $e) { - // @todo throw an exception due to an incomplete schema. - // Fix as part of https://drupal.org/node/2183983. - } - } - else { - // Throw exception on any non-scalar or non-array value. - if (!is_array($value)) { - throw new UnsupportedDataTypeConfigException(String::format('Invalid data type for config element @name:@key', array( - '@name' => $this->getName(), - '@key' => $key, - ))); - } - // Recurse into any nested keys. - foreach ($value as $nested_value_key => $nested_value) { - $value[$nested_value_key] = $this->castValue($key . '.' . $nested_value_key, $nested_value); - } - } - return $value; - } - - /** * Gets the raw data without overrides. * * @return array @@ -607,5 +291,5 @@ public function getOriginal($key = '', $apply_overrides = TRUE) { } } } -} +} diff --git a/core/lib/Drupal/Core/Config/ConfigBase.php b/core/lib/Drupal/Core/Config/ConfigBase.php new file mode 100644 index 0000000..6240c7b --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigBase.php @@ -0,0 +1,214 @@ +name; + } + + /** + * Sets the name of this configuration object. + * + * @param string $name + * The name of the configuration object. + * + * @return $this + * The configuration object. + */ + public function setName($name) { + $this->name = $name; + return $this; + } + + /** + * Validates the configuration object name. + * + * @param string $name + * The name of the configuration object. + * + * @throws \Drupal\Core\Config\ConfigNameException + * + * @see Config::MAX_NAME_LENGTH + */ + public static function validateName($name) { + // The name must be namespaced by owner. + if (strpos($name, '.') === FALSE) { + throw new ConfigNameException(String::format('Missing namespace in Config object name @name.', array( + '@name' => $name, + ))); + } + // The name must be shorter than Config::MAX_NAME_LENGTH characters. + if (strlen($name) > self::MAX_NAME_LENGTH) { + throw new ConfigNameException(String::format('Config object name @name exceeds maximum allowed length of @length characters.', array( + '@name' => $name, + '@length' => self::MAX_NAME_LENGTH, + ))); + } + + // The name must not contain any of the following characters: + // : ? * < > " ' / \ + if (preg_match('/[:?*<>"\'\/\\\\]/', $name)) { + throw new ConfigNameException(String::format('Invalid character in Config object name @name.', array( + '@name' => $name, + ))); + } + } + + /** + * Gets data from this configuration object. + * + * @param string $key + * A string that maps to a key within the configuration data. + * For instance in the following configuration array: + * @code + * array( + * 'foo' => array( + * 'bar' => 'baz', + * ), + * ); + * @endcode + * A key of 'foo.bar' would return the string 'baz'. However, a key of 'foo' + * would return array('bar' => 'baz'). + * If no key is specified, then the entire data array is returned. + * + * @return mixed + * The data that was requested. + */ + public function get($key = '') { + if (empty($key)) { + return $this->data; + } + else { + $parts = explode('.', $key); + if (count($parts) == 1) { + return isset($this->data[$key]) ? $this->data[$key] : NULL; + } + else { + $value = NestedArray::getValue($this->data, $parts, $key_exists); + return $key_exists ? $value : NULL; + } + } + } + + /** + * Replaces the data of this configuration object. + * + * @param array $data + * The new configuration data. + * + * @return $this + * The configuration object. + */ + public function setData(array $data) { + $this->data = $data; + return $this; + } + + /** + * Sets a value in this configuration object. + * + * @param string $key + * Identifier to store value in configuration. + * @param mixed $value + * Value to associate with identifier. + * + * @return $this + * The configuration object. + */ + public function set($key, $value) { + // The dot/period is a reserved character; it may appear between keys, but + // not within keys. + $parts = explode('.', $key); + if (count($parts) == 1) { + $this->data[$key] = $value; + } + else { + NestedArray::setValue($this->data, $parts, $value); + } + return $this; + } + + /** + * Unsets a value in this configuration object. + * + * @param string $key + * Name of the key whose value should be unset. + * + * @return $this + * The configuration object. + */ + public function clear($key) { + $parts = explode('.', $key); + if (count($parts) == 1) { + unset($this->data[$key]); + } + else { + NestedArray::unsetValue($this->data, $parts); + } + return $this; + } + + /** + * Merges data into a configuration object. + * + * @param array $data_to_merge + * An array containing data to merge. + * + * @return $this + * The configuration object. + */ + public function merge ($data) { + return $this->setData(NestedArray::mergeDeepArray(array($this->data, $data), TRUE)); + } + +} diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index 5c4ef49..04acb73 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -123,7 +123,7 @@ 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->typedConfigManager, $this->eventDispatcher); + $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); if ($this->useOverrides) { // Get and apply any overrides. @@ -171,7 +171,7 @@ public function loadMultiple(array $names) { foreach ($storage_data as $name => $data) { $cache_key = $this->getCacheKey($name); - $this->cache[$cache_key] = new Config($name, $this->storage, $this->typedConfigManager, $this->eventDispatcher); + $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); $this->cache[$cache_key]->initWithData($data); if ($this->useOverrides) { if (isset($module_overrides[$name])) { diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php index 6b1909d..5cc1a95 100644 --- a/core/lib/Drupal/Core/Config/ConfigImporter.php +++ b/core/lib/Drupal/Core/Config/ConfigImporter.php @@ -266,7 +266,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->typedConfigManager, $this->eventDispatcher); + $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager); if ($op == 'delete') { $config->delete(); } @@ -303,13 +303,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->typedConfigManager, $this->eventDispatcher); + $old_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager); 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->typedConfigManager, $this->eventDispatcher); + $new_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager); 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 5c87238..06477ec 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -113,7 +113,7 @@ public function installDefaultConfig($type, $name) { continue; } - $new_config = new Config($config_name, $this->activeStorage, $this->typedConfig, $this->eventDispatcher); + $new_config = new Config($config_name, $this->activeStorage, $this->eventDispatcher, $this->typedConfig); $data = $source_storage->read($config_name); if ($data !== FALSE) { $new_config->setData($data); diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php new file mode 100644 index 0000000..8b05f95 --- /dev/null +++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php @@ -0,0 +1,185 @@ +isNew = FALSE; + $this->setData($data); + $this->originalData = $this->data; + return $this; + } + + /** + * Returns whether this configuration object is new. + * + * @return bool + * TRUE if this configuration object does not exist in storage. + */ + public function isNew() { + return $this->isNew; + } + + /** + * Retrieves the storage used to load and save this configuration object. + * + * @return \Drupal\Core\Config\StorageInterface + * The configuration storage object. + */ + public function getStorage() { + return $this->storage; + } + + /** + * Gets the schema wrapper for the whole configuration object. + * + * The schema wrapper is dependent on the configuration name and the whole + * data structure, so if the name or the data changes in any way, the wrapper + * should be reset. + * + * @return \Drupal\Core\Config\Schema\Element + */ + protected function getSchemaWrapper() { + if (!isset($this->schemaWrapper)) { + $definition = $this->typedConfigManager->getDefinition($this->name); + $this->schemaWrapper = $this->typedConfigManager->create($definition, $this->data); + } + return $this->schemaWrapper; + } + + /** + * Casts the value to correct data type using the configuration schema. + * + * @param string $key + * A string that maps to a key within the configuration data. + * @param string $value + * Value to associate with the key. + * + * @return mixed + * The value cast to the type indicated in the schema. + * + * @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException + * Exception on unsupported/undefined data type deducted. + */ + protected function castValue($key, $value) { + if ($value === NULL) { + $value = NULL; + } + elseif (is_scalar($value)) { + try { + $element = $this->getSchemaWrapper()->get($key); + if ($element instanceof PrimitiveInterface) { + // Special handling for integers and floats since the configuration + // system is primarily concerned with saving values from the Form API + // we have to special case the meaning of an empty string for numeric + // types. In PHP this would be casted to a 0 but for the purposes of + // configuration we need to treat this as a NULL. + if ($value === '' && ($element instanceof IntegerInterface || $element instanceof FloatInterface)) { + $value = NULL; + } + else { + $value = $element->getCastedValue(); + } + } + else { + // Config only supports primitive data types. If the config schema + // does define a type $element will be an instance of + // \Drupal\Core\Config\Schema\Property. Convert it to string since it + // is the safest possible type. + $value = $element->getString(); + } + } + catch (SchemaIncompleteException $e) { + // @todo throw an exception due to an incomplete schema. + // Fix as part of https://drupal.org/node/2183983. + } + } + else { + // Throw exception on any non-scalar or non-array value. + if (!is_array($value)) { + throw new UnsupportedDataTypeConfigException(String::format('Invalid data type for config element @name:@key', array( + '@name' => $this->getName(), + '@key' => $key, + ))); + } + // Recurse into any nested keys. + foreach ($value as $nested_value_key => $nested_value) { + $value[$nested_value_key] = $this->castValue($key . '.' . $nested_value_key, $nested_value); + } + } + return $value; + } + +} diff --git a/core/lib/Drupal/Core/Theme/ThemeSettings.php b/core/lib/Drupal/Core/Theme/ThemeSettings.php index d20b843..9f94b56 100644 --- a/core/lib/Drupal/Core/Theme/ThemeSettings.php +++ b/core/lib/Drupal/Core/Theme/ThemeSettings.php @@ -7,12 +7,12 @@ namespace Drupal\Core\Theme; -use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Config\ConfigBase; /** * Defines the default theme settings object. */ -class ThemeSettings { +class ThemeSettings extends ConfigBase { /** * The theme of the theme settings object. @@ -22,13 +22,6 @@ class ThemeSettings { protected $theme; /** - * The data of the theme settings object. - * - * @var array - */ - protected $data; - - /** * Constructs a theme settings object. * * @param string $name @@ -36,7 +29,6 @@ class ThemeSettings { */ public function __construct($theme) { $this->theme = $theme; - $this->data = array(); } /** @@ -49,112 +41,4 @@ public function getTheme() { return $this->theme; } - /** - * Gets data from this theme settings object. - * - * @param string $key - * A string that maps to a key within the theme settings data. - * For instance in the following theme settings array: - * @code - * array( - * 'foo' => array( - * 'bar' => 'baz', - * ), - * ); - * @endcode - * A key of 'foo.bar' would return the string 'baz'. However, a key of 'foo' - * would return array('bar' => 'baz'). - * If no key is specified, then the entire data array is returned. - * - * - * @return mixed - * The data that was requested. - */ - public function get($key = '') { - if (empty($key)) { - return $this->data; - } - else { - $parts = explode('.', $key); - if (count($parts) == 1) { - return isset($this->data[$key]) ? $this->data[$key] : NULL; - } - else { - $value = NestedArray::getValue($this->data, $parts, $key_exists); - return $key_exists ? $value : NULL; - } - } - } - - /** - * Replaces the data of this theme settings object. - * - * @param array $data - * The new theme settings data. - * - * @return \Drupal\Core\Theme\ThemeSettings - * The theme settings object. - */ - public function setData(array $data) { - $this->data = $data; - return $this; - } - - /** - * Sets value in this theme settings object. - * - * @param string $key - * Identifier to store value in theme settings. - * @param string $value - * Value to associate with identifier. - * - * @return \Drupal\Core\Theme\ThemeSettings - * The theme settings object. - */ - public function set($key, $value) { - // The dot/period is a reserved character; it may appear between keys, but - // not within keys. - $parts = explode('.', $key); - if (count($parts) == 1) { - $this->data[$key] = $value; - } - else { - NestedArray::setValue($this->data, $parts, $value); - } - return $this; - } - - /** - * Unsets value in this theme settings object. - * - * @param string $key - * Name of the key whose value should be unset. - * - * @return \Drupal\Core\Theme\ThemeSettings - * The theme settings object. - */ - public function clear($key) { - $parts = explode('.', $key); - if (count($parts) == 1) { - unset($this->data[$key]); - } - else { - NestedArray::unsetValue($this->data, $parts); - } - return $this; - } - - /** - * Merges the data into this theme settings object. - * - * @param array $data - * Theme settings data to merge. - * - * @return \Drupal\Core\Theme\ThemeSettings - * The theme settings object. - */ - public function mergeData ($data) { - $this->data = NestedArray::mergeDeep($this->data, $data); - return $this; - } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php index 48c8727..27e8845 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('config.typed'), \Drupal::service('event_dispatcher')); + $config = new Config($name, \Drupal::service('config.storage'), \Drupal::service('event_dispatcher'), \Drupal::service('config.typed')); $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/ConfigLanguageOverrideTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php index 9d2655a..e0d5b6b 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php @@ -71,8 +71,9 @@ function testConfigLanguageOverride() { // this should only happen for configuration entities as we should not be // creating simple configuration objects on the fly. \Drupal::languageManager() - ->config('config_test.new', language_load('de')) - ->set('language', 'override')->save(); + ->getLanguageConfigOverride('de', 'config_test.new') + ->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'); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php index 01cda65..34f5172 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php @@ -45,11 +45,8 @@ 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. - $language = language_load('xx'); \Drupal::languageManager() - ->config('system.site', $language) + ->getLanguageConfigOverride($langcode, 'system.site') ->set('name', 'XX site name') ->save(); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php index 112eeb3..6deab96 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php @@ -61,7 +61,7 @@ public function testOverridePriorities() { )); \Drupal::languageManager()->setConfigOverrideLanguage($language); \Drupal::languageManager() - ->config('system.site', $language) + ->getLanguageConfigOverride($language->id, 'system.site') ->set('name', $language_overridden_name) ->set('mail', $language_overridden_mail) ->save(); 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 9a894d6..fe79059 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 @@ -11,7 +11,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\ConfirmFormBase; -use Drupal\language\Config\LanguageStorageInterface; +use Drupal\language\ConfigurableLanguageManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -22,11 +22,11 @@ class ConfigTranslationDeleteForm extends ConfirmFormBase { /** - * The language override configuration storage. + * The language manager. * - * @var \Drupal\language\Config\LanguageStorageInterface $config_storage + * @var \Drupal\language\ConfigurableLanguageManagerInterface */ - protected $configStorage; + protected $languageManager; /** * The configuration mapper manager. @@ -59,15 +59,15 @@ class ConfigTranslationDeleteForm extends ConfirmFormBase { /** * Constructs a ConfigTranslationDeleteForm. * - * @param \Drupal\language\Config\LanguageStorageInterface $config_storage + * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager * 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. */ - public function __construct(LanguageStorageInterface $config_storage, ConfigMapperManagerInterface $config_mapper_manager, ModuleHandlerInterface $module_handler) { - $this->configStorage = $config_storage; + public function __construct(ConfigurableLanguageManagerInterface $language_manager, ConfigMapperManagerInterface $config_mapper_manager, ModuleHandlerInterface $module_handler) { + $this->languageManager = $language_manager; $this->configMapperManager = $config_mapper_manager; $this->moduleHandler = $module_handler; } @@ -77,7 +77,7 @@ public function __construct(LanguageStorageInterface $config_storage, ConfigMapp */ public static function create(ContainerInterface $container) { return new static( - $container->get('language.config_storage'), + $container->get('language_manager'), $container->get('plugin.manager.config_translation.mapper'), $container->get('module_handler') ); @@ -136,9 +136,8 @@ 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) { - $this->configStorage->delete($name); + $this->languageManager->getLanguageConfigOverride($this->language->id, $name)->delete(); } // 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 474d0a3..ebbf17f 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\Config\LanguageConfigOverride; use Drupal\language\ConfigurableLanguageManagerInterface; use Drupal\locale\StringStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -227,18 +228,18 @@ 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 = $this->languageManager->config($name, $this->language); + $config_translation = $this->languageManager->getLanguageConfigOverride($this->language->id, $name); $locations = $this->localeStorage->getLocations(array('type' => 'configuration', 'name' => $name)); - $this->setConfig($this->language, $base_config, $translation_config, $form_values[$name], !empty($locations)); + $this->setConfig($this->language, $base_config, $config_translation, $form_values[$name], !empty($locations)); // If no overrides, delete language specific configuration file. - $saved_config = $translation_config->get(); + $saved_config = $config_translation->get(); if (empty($saved_config)) { - $translation_config->delete(); + $config_translation->delete(); } else { - $translation_config->save(); + $config_translation->save(); } } $this->configFactory->setOverrideState($old_state); @@ -354,9 +355,8 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d * Set the configuration in this language. * @param \Drupal\Core\Config\Config $base_config * Base configuration values, in the source language. - * @param \Drupal\Core\Config\Config $translation_config - * Translation configuration instance. Values from $config_values will be - * set in this instance. + * @param \Drupal\language\Config\LanguageConfigOverride $config_translation + * Translation configuration override data. * @param array $config_values * A simple one dimensional or recursive array: * - simple: @@ -371,12 +371,15 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d * @param bool $shipped_config * (optional) Flag to specify whether the configuration had a shipped * version and therefore should also be stored in the locale database. + * + * @return array + * Translation configuration override data. */ - protected function setConfig(Language $language, Config $base_config, Config $translation_config, array $config_values, $shipped_config = FALSE) { + protected function setConfig(Language $language, Config $base_config, LanguageConfigOverride $config_translation, array $config_values, $shipped_config = FALSE) { foreach ($config_values as $key => $value) { if (is_array($value) && !isset($value['translation'])) { // Traverse into this level in the configuration. - $this->setConfig($language, $base_config, $translation_config, $value, $shipped_config); + $this->setConfig($language, $base_config, $config_translation, $value, $shipped_config); } else { @@ -406,10 +409,10 @@ protected function setConfig(Language $language, Config $base_config, Config $tr // Save value, if different from the source value in the base // configuration. If same as original configuration, remove override. if ($base_config->get($key) !== $value['translation']) { - $translation_config->set($key, $value['translation']); + $config_translation->set($key, $value['translation']); } else { - $translation_config->clear($key); + $config_translation->clear($key); } } } 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 1997925..405aaf5 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,14 +177,14 @@ public function testSourceValueDuplicateSave() { $this->drupalPostForm("$translation_base_url/fr/add", $edit, t('Save translation')); // Read overridden file from active config. - $config = \Drupal::languageManager()->config('system.site', language_load('fr')); + $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'system.site'); // Expect both name and slogan in language specific file. $expected = array( 'name' => 'FR ' . $site_name, 'slogan' => 'FR ' . $site_slogan, ); - $this->assertEqual($expected, $config->get()); + $this->assertEqual($expected, $override->get()); // Case 2: Update new value for site slogan and default value for site name. $this->drupalGet("$translation_base_url/fr/edit"); @@ -198,11 +198,11 @@ public function testSourceValueDuplicateSave() { ); $this->drupalPostForm(NULL, $edit, t('Save translation')); $this->assertRaw(t('Successfully updated @language translation.', array('@language' => 'French'))); - $config = \Drupal::languageManager()->config('system.site', language_load('fr')); + $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'system.site'); // Expect only slogan in language specific file. - $expected = array('slogan' => 'FR ' . $site_slogan); - $this->assertEqual($expected, $config->get()); + $expected = 'FR ' . $site_slogan; + $this->assertEqual($expected, $override->get('slogan')); // Case 3: Keep default value for site name and slogan. $this->drupalGet("$translation_base_url/fr/edit"); @@ -212,10 +212,10 @@ public function testSourceValueDuplicateSave() { 'config_names[system.site][slogan][translation]' => $site_slogan, ); $this->drupalPostForm(NULL, $edit, t('Save translation')); - $config = \Drupal::languageManager()->config('system.site', language_load('fr')); + $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'system.site'); // Expect no language specific file. - $this->assertTrue($config->isNew()); + $this->assertTrue($override->isNew()); // Check configuration page with translator user. Should have no access. $this->drupalLogout(); @@ -281,12 +281,12 @@ public function testContactConfigEntityTranslation() { $this->drupalPostForm($translation_page_url, $edit, t('Save translation')); // Expect translated values in language specific file. - $config = \Drupal::languageManager()->config('contact.category.feedback', language_load($langcode)); + $override = \Drupal::languageManager()->getLanguageConfigOverride($langcode, 'contact.category.feedback'); $expected = array( 'label' => 'Website feedback - ' . $langcode, 'reply' => 'Thank you for your mail - ' . $langcode, ); - $this->assertEqual($expected, $config->get()); + $this->assertEqual($expected, $override->get()); // Check for edit, delete links (and no 'add' link) for $langcode. $this->assertNoLinkByHref("$translation_base_url/$langcode/add"); @@ -344,8 +344,8 @@ public function testContactConfigEntityTranslation() { $this->assertNoLinkByHref("$translation_base_url/$langcode/delete"); // Expect no language specific file present anymore. - $config = \Drupal::languageManager()->config('contact.category.feedback', language_load($langcode)); - $this->assertTrue($config->isNew()); + $override = \Drupal::languageManager()->getLanguageConfigOverride($langcode, 'contact.category.feedback'); + $this->assertTrue($override->isNew()); } // Check configuration page with translator user. Should have no access. @@ -411,12 +411,12 @@ public function testDateFormatTranslation() { $this->drupalPostForm($translation_page_url, $edit, t('Save translation')); // Get translation and check we've got the right value. - $config = \Drupal::languageManager()->config('system.date_format.' . $id, language_load('fr')); + $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'system.date_format.' . $id); $expected = array( 'label' => $id . ' - FR', 'pattern' => array('php' => 'D'), ); - $this->assertEqual($expected, $config->get()); + $this->assertEqual($expected, $override->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 95f9c97..13141a6 100644 --- a/core/modules/language/language.services.yml +++ b/core/modules/language/language.services.yml @@ -20,12 +20,12 @@ services: factory_service: cache_factory arguments: [language_config] language.config_storage: - class: Drupal\language\Config\LanguageStorage + class: Drupal\language\Config\LanguageOverrideStorage arguments: ['@language.cache_config'] tags: - { name: persist } language.config_factory_override: - class: Drupal\language\Config\LanguageConfigOverride + class: Drupal\language\Config\LanguageConfigFactoryOverride arguments: ['@language.default', '@language.config_storage', '@config.typed'] tags: - { name: config.factory.override, priority: -254 } diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php similarity index 84% copy from core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php copy to core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php index 58b261e..7eaf42a 100644 --- a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\language\Config\LanguageConfigOverride. + * Contains \Drupal\language\Config\LanguageConfigFactoryOverride. */ namespace Drupal\language\Config; @@ -13,12 +13,12 @@ use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageDefault; -class LanguageConfigOverride implements LanguageConfigOverrideInterface { +class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInterface { /** * The language configuration storage. * - * @var \Drupal\language\Config\LanguageStorage + * @var \Drupal\language\Config\LanguageOverrideStorage */ protected $storage; @@ -30,16 +30,16 @@ class LanguageConfigOverride implements LanguageConfigOverrideInterface { protected $language; /** - * Constructs the LanguageConfigOverride object. + * Constructs the LanguageConfigFactoryOverride object. * * @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. - * @param \Drupal\language\Config\LanguageStorageInterface $storage + * @param \Drupal\language\Config\LanguageOverrideStorageInterface $storage * The language configuration storage. */ - public function __construct(LanguageDefault $language_default, LanguageStorageInterface $storage, TypedConfigManagerInterface $typed_config) { + public function __construct(LanguageDefault $language_default, LanguageOverrideStorageInterface $storage, TypedConfigManagerInterface $typed_config) { // 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. @@ -80,7 +80,7 @@ public function install($type, $name) { $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 = new LanguageConfigOverride($config_name, $this->storage, $this->typedConfig); $config->setData($data)->save(); } } @@ -104,7 +104,7 @@ public function uninstall($type, $name) { $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 = new LanguageConfigOverride($config_name, $this->storage, $this->typedConfig); $config->delete(); } } diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php similarity index 80% rename from core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php rename to core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php index 63467e7..5eadad3 100644 --- a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\language\Config\LanguageConfigOverrideInterface. + * Contains \Drupal\language\Config\LanguageConfigFactoryOverrideInterface. */ namespace Drupal\language\Config; @@ -10,7 +10,7 @@ use Drupal\Core\Config\ConfigFactoryOverrideInterface; use Drupal\Core\Language\Language; -interface LanguageConfigOverrideInterface extends ConfigFactoryOverrideInterface { +interface LanguageConfigFactoryOverrideInterface extends ConfigFactoryOverrideInterface { /** * Gets the language object used to override configuration data. diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php index 58b261e..bc2f2d2 100644 --- a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php @@ -2,130 +2,71 @@ /** * @file - * Contains \Drupal\language\Config\LanguageConfigOverride. + * Definition of Drupal\language\Config\LanguageConfigOverride. */ namespace Drupal\language\Config; -use Drupal\Core\Config\FileStorage; -use Drupal\Core\Config\Config; +use Drupal\Core\Config\StorableConfigBase; +use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\TypedConfigManagerInterface; -use Drupal\Core\Language\Language; -use Drupal\Core\Language\LanguageDefault; -class LanguageConfigOverride implements LanguageConfigOverrideInterface { - - /** - * The language configuration storage. - * - * @var \Drupal\language\Config\LanguageStorage - */ - protected $storage; - - /** - * The language object used to override configuration data. - * - * @var \Drupal\Core\Language\Language - */ - protected $language; +/** + * Defines the default configuration object. + */ +class LanguageConfigOverride extends StorableConfigBase { /** - * Constructs the LanguageConfigOverride object. + * Constructs a configuration object. * - * @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. - * @param \Drupal\language\Config\LanguageStorageInterface $storage - * The language configuration storage. - */ - public function __construct(LanguageDefault $language_default, LanguageStorageInterface $storage, TypedConfigManagerInterface $typed_config) { - // 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. - $this->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} + * @param string $name + * The name of the configuration object being constructed. + * @param \Drupal\Core\Config\StorageInterface $storage + * A storage controller object to use for reading and writing the + * configuration data. + * @param \Drupal\Core\Config\TypedConfigManager $typed_config + * The typed configuration manager service. */ - public function getCacheSuffix() { - return $this->language->id; + public function __construct($name, StorageInterface $storage, TypedConfigManagerInterface $typed_config) { + $this->name = $name; + $this->storage = $storage; + $this->typedConfigManager = $typed_config; } /** * {@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(); - } - } - } - } - } + public function save() { + // Validate the configuration object name before saving. + static::validateName($this->name); - /** - * {@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(); - } - } + // If there is a schema for this configuration object, cast all values to + // conform to the schema. + if ($this->typedConfigManager->hasConfigSchema($this->name)) { + // Ensure that the schema wrapper has the latest data. + $this->schemaWrapper = NULL; + foreach ($this->data as $key => $value) { + $this->data[$key] = $this->castValue($key, $value); } } - } - /** - * {@inheritdoc} - */ - public function getLanguage() { - return $this->language; + $this->storage->write($this->name, $this->data); + $this->isNew = FALSE; + $this->originalData = $this->data; + return $this; } /** * {@inheritdoc} */ - public function setLanguage(Language $language = NULL) { - $this->language = $language; - $this->storage->setLangcode($this->language->id); + public function delete() { + // @todo Consider to remove the pruning of data for Config::delete(). + $this->data = array(); + $this->storage->delete($this->name); + $this->isNew = TRUE; + $this->originalData = $this->data; return $this; } } + diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageStorage.php b/core/modules/language/lib/Drupal/language/Config/LanguageOverrideStorage.php similarity index 90% rename from core/modules/language/lib/Drupal/language/Config/LanguageStorage.php rename to core/modules/language/lib/Drupal/language/Config/LanguageOverrideStorage.php index 3ecef1e..256191e 100644 --- a/core/modules/language/lib/Drupal/language/Config/LanguageStorage.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageOverrideStorage.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\language\Config\LanguageStorage. + * Contains \Drupal\language\Config\LanguageOverrideStorage. */ namespace Drupal\language\Config; @@ -11,7 +11,7 @@ use Drupal\Core\Config\CachedStorage; use Drupal\Core\Config\FileStorage; -class LanguageStorage extends CachedStorage implements LanguageStorageInterface { +class LanguageOverrideStorage extends CachedStorage implements LanguageOverrideStorageInterface { /** * The langcode that determines the configuration override storage directory. @@ -118,8 +118,8 @@ protected function getCacheKey($name) { * {@inheritdoc} */ protected function getCacheKeys(array $names) { - foreach ($names as &$name) { - $name = $this->getCacheKey($name); + foreach ($names as $name) { + $names[$name] = $this->getCacheKey($name); } return $names; } @@ -136,8 +136,8 @@ protected function getNameFromCacheKey($key) { * {@inheritdoc} */ protected function getNamesFromCacheKeys($keys) { - foreach ($keys as &$key) { - $key = $this->getNameFromCacheKey($key); + foreach ($keys as $key) { + $keys[$key] = $this->getNameFromCacheKey($key); } return $keys; } diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageOverrideStorageInterface.php similarity index 73% rename from core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php rename to core/modules/language/lib/Drupal/language/Config/LanguageOverrideStorageInterface.php index d16bad1..5e31cc8 100644 --- a/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageOverrideStorageInterface.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\language\Config\LanguageStorage. + * Contains \Drupal\language\Config\LanguageOverrideStorageInterface. */ namespace Drupal\language\Config; @@ -10,7 +10,7 @@ use Drupal\Core\Config\StorageCacheInterface; use Drupal\Core\Config\StorageInterface; -interface LanguageStorageInterface extends StorageInterface, StorageCacheInterface { +interface LanguageOverrideStorageInterface extends StorageInterface, StorageCacheInterface { /** * Sets the langcode to determine the override configuration directory to use. diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php index c67fa09..2cf8459 100644 --- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php +++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php @@ -8,15 +8,15 @@ namespace Drupal\language; use Drupal\Component\PhpStorage\PhpStorageFactory; -use Drupal\Core\Config\Config; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageDefault; use Drupal\Core\Language\LanguageManager; -use Drupal\language\Config\LanguageConfigOverrideInterface; -use Drupal\language\Config\LanguageStorageInterface; +use Drupal\language\Config\LanguageConfigFactoryOverrideInterface; +use Drupal\language\Config\LanguageConfigOverride; +use Drupal\language\Config\LanguageOverrideStorageInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -41,16 +41,16 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl /** * The language configuration override service. * - * @var \Drupal\language\Config\LanguageConfigOverrideInterface + * @var \Drupal\language\Config\LanguageConfigFactoryOverrideInterface */ protected $configFactoryOverride; /** - * The language configuration storage service. + * The language configuration override storage service. * - * @var \Drupal\language\Config\LanguageStorageInterface + * @var \Drupal\language\Config\LanguageOverrideStorageInterface */ - protected $configStorage; + protected $configOverrideStorage; /** * The typed config manager. @@ -124,19 +124,19 @@ public static function rebuildServices() { * The configuration factory service. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler service. - * @param \Drupal\language\Config\LanguageConfigOverrideInterface $config_override + * @param \Drupal\language\Config\LanguageConfigFactoryOverrideInterface $config_override * The language configuration override service. - * @param \Drupal\language\Config\LanguageStorageInterface $config_storage + * @param \Drupal\language\Config\LanguageOverrideStorageInterface $config_storage * The language configuration storage service. * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config * The typed configuration manager. */ - public function __construct(LanguageDefault $default_language, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, LanguageConfigOverrideInterface $config_override, LanguageStorageInterface $config_storage, TypedConfigManagerInterface $typed_config) { + public function __construct(LanguageDefault $default_language, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, LanguageConfigFactoryOverrideInterface $config_override, LanguageOverrideStorageInterface $config_storage, TypedConfigManagerInterface $typed_config) { $this->defaultLanguage = $default_language; $this->configFactory = $config_factory; $this->moduleHandler = $module_handler; $this->configFactoryOverride = $config_override; - $this->configStorage = $config_storage; + $this->configOverrideStorage = $config_storage; $this->typedConfig = $typed_config; } @@ -425,14 +425,22 @@ public function getConfigOverrideLanguage() { /** * {@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); + public function getLanguageConfigOverride($langcode, $name) { + $storage = $this->getLanguageOverrideStorage($langcode); + $override = new LanguageConfigOverride($name, $storage, $this->typedConfig); + if ($data = $storage->read($name)) { + $override->initWithData($data); } - return $config; + return $override; + } + + /** + * {@inheritdoc} + */ + public function getLanguageOverrideStorage($langcode) { + // Clone the language override storage so a process could compare language + // overrides if it wanted to. + return clone $this->configOverrideStorage->setLangcode($langcode); } } diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php index 9651c86..5e08205 100644 --- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php +++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php @@ -79,16 +79,27 @@ public function saveLanguageTypesConfiguration(array $config); public function updateLockedLanguageWeights(); /** - * Gets a language override configuration object. + * Gets a language config override object. * - * @param $name - * The configuration object name. - * @param \Drupal\Core\Language\Language $language - * The language to get the configuration object for. + * @param string $langcode + * The langcode. + * @param string $name + * The language configuration override object name. * - * @return \Drupal\Core\Config\Config - * The language override configuration object. + * @return \Drupal\language\Config\LanguageConfigOverride + * The language config override object. */ - public function config($name, Language $language); + public function getLanguageConfigOverride($langcode, $name); + + /** + * Gets the language override configuration override storage for a langcode. + * + * @param string $langcode + * The langcode. + * + * @return \Drupal\language\Config\LanguageOverrideStorage + * The language override storage. + */ + public function getLanguageOverrideStorage($langcode); } diff --git a/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php index 8741057..7700611 100644 --- a/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php +++ b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php @@ -10,7 +10,6 @@ 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; diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php index bb9d197..94bd547 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php @@ -12,7 +12,8 @@ use Drupal\Core\Config\TypedConfigManager; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\language\Config\LanguageStorageInterface; +use Drupal\language\Config\LanguageOverrideStorageInterface; +use Drupal\language\ConfigurableLanguageManagerInterface; /** * Manages localized configuration type plugins. @@ -46,11 +47,11 @@ class LocaleConfigManager extends TypedConfigManager { protected $configFactory; /** - * The language configuration storage. + * The language manager. * - * @var \Drupal\language\Config\LanguageStorageInterface + * @var \Drupal\language\ConfigurableLanguageManagerInterface */ - protected $languageStorage; + protected $languageManager; /** * Creates a new typed configuration manager. @@ -68,16 +69,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. + * @param \Drupal\language\ConfigurableLanguageManagerInterface + * The language manager. */ - public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory, LanguageStorageInterface $language_storage) { + public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory, ConfigurableLanguageManagerInterface $language_manager) { // 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; + $this->languageManager = $language_manager; } /** @@ -144,7 +145,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) { - $this->languageStorage->setLangcode($langcode)->write($name, $data); + $this->languageManager->getLanguageConfigOverride($langcode, $name)->setData($data)->save(); } /** @@ -156,7 +157,7 @@ public function saveTranslationData($name, $langcode, array $data) { * Language code. */ public function deleteTranslationData($name, $langcode) { - $this->languageStorage->setLangcode($langcode)->delete($name); + $this->languageManager->getLanguageConfigOverride($langcode, $name)->delete(); } /** @@ -229,9 +230,9 @@ public function getStringNames(array $lids) { * Language code to delete. */ public function deleteLanguageTranslations($langcode) { - $this->languageStorage->setLangcode($langcode); - foreach ($this->languageStorage->listAll() as $name) { - $this->languageStorage->delete($name); + $storage = $this->languageManager->getLanguageOverrideStorage($langcode); + foreach ($storage->listAll() as $name) { + $this->languageManager->getLanguageConfigOverride($langcode, $name)->delete(); } } @@ -314,8 +315,8 @@ public function translateString($name, $langcode, $source, $context) { * A boolean indicating if a language has configuration translations. */ public function hasTranslation($name, Language $language) { - $translation = $this->languageStorage->setLangcode($language->id)->read($name); - return !empty($translation); + $translation = $this->languageManager->getLanguageConfigOverride($language->id, $name); + return !$translation->isNew(); } } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php index 36e51a9..453743c 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php @@ -47,7 +47,7 @@ public function testHasTranslation() { $this->container->get('locale.storage'), $this->container->get('cache.config'), $this->container->get('config.factory'), - $this->container->get('language.config_storage') + $this->container->get('language_manager') ); $language = new Language(array('id' => 'de')); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php index 5594d25..48a0132 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php @@ -171,16 +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. - $config = \Drupal::languageManager()->config('image.style.medium', language_load('xx')); - $this->assertEqual($config->get('label'), $image_style_label); + $override = \Drupal::languageManager()->getLanguageConfigOverride('xx', 'image.style.medium'); + $this->assertEqual($override->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. - $config = \Drupal::languageManager()->config('image.style.medium', language_load('xx')); - $this->assertFalse($config->get('label'), 'Translated configuration for image module removed.'); + $override = \Drupal::languageManager()->getLanguageConfigOverride('xx', 'image.style.medium'); + $this->assertTrue($override->isNew(), '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 250e648..7a0f0d7 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', '@language.config_storage'] + arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory', '@language_manager'] locale.storage: class: Drupal\locale\StringDatabaseStorage arguments: ['@database']