Commit 81fbebac authored by webchick's avatar webchick

Issue #2215413 by Eli-T, alexpott: Split the Config class into...

Issue #2215413 by Eli-T, alexpott: Split the Config class into StorableConfigBase and ConfigBase. Make ThemeSettings inherit from ConfigBase.
parent 50eb8009
......@@ -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.
......
......@@ -9,9 +9,7 @@
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;
......@@ -21,20 +19,7 @@
/**
* 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.
*
......@@ -45,38 +30,10 @@ class Config extends DependencySerialization {
/**
* The language object used to override configuration data.
*
* @var Drupal\Core\Language\Language
* @var \Drupal\Core\Language\Language
*/
protected $language;
/**
* The name of the configuration object.
*
* @var string
*/
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.
*
......@@ -102,25 +59,11 @@ class Config extends DependencySerialization {
protected $moduleOverrides;
/**
* The storage used to load and save this configuration object.
*
* @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.
* The current settings overrides.
*
* @var \Drupal\Core\Config\TypedConfigManager
* @var array
*/
protected $typedConfigManager;
protected $settingsOverrides;
/**
* Constructs a configuration object.
......@@ -146,111 +89,19 @@ public function __construct($name, StorageInterface $storage, EventDispatcherInt
}
/**
* 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) {
parent::initWithData($data);
$this->settingsOverrides = array();
$this->languageOverrides = array();
$this->moduleOverrides = array();
$this->isNew = FALSE;
$this->replaceData($data);
$this->originalData = $this->data;
$this->setData($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)) {
......@@ -272,33 +123,9 @@ 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;
......@@ -391,56 +218,25 @@ 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);
}
parent::set($key, $value);
$this->resetOverriddenData();
return $this;
}
/**
* 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);
}
parent::clear($key);
$this->resetOverriddenData();
return $this;
}
/**
* Saves the configuration object.
*
* @return \Drupal\Core\Config\Config
* The configuration object.
* {@inheritdoc}
*/
public function save() {
// Validate the configuration object name before saving.
......@@ -501,7 +297,7 @@ public function getStorage() {
*/
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));
$this->setData(NestedArray::mergeDeepArray(array($this->data, $data_to_merge), TRUE));
return $this;
}
......@@ -651,4 +447,3 @@ public function getOriginal($key = '', $apply_overrides = TRUE) {
}
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Config\ConfigBase.
*/
namespace Drupal\Core\Config;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\String;
use \Drupal\Core\DependencyInjection\DependencySerialization;
abstract class ConfigBase extends DependencySerialization {
/**
* The name of the configuration object.
*
* @var string
*/
protected $name;
/**
* The data of the configuration object.
*
* @var array
*/
protected $data = array();
/**
* 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
*
* Configuration objects not stored on the filesystem should still be
* restricted in name length so name can be used as a cache key.
*/
const MAX_NAME_LENGTH = 250;
/**
* 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 $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(array $data_to_merge) {
return $this->setData(NestedArray::mergeDeepArray(array($this->data, $data_to_merge), TRUE));
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Config\StorableConfigBase.
*/
namespace Drupal\Core\Config;
use Drupal\Component\Utility\String;
use Drupal\Core\Config\Schema\SchemaIncompleteException;
use Drupal\Core\TypedData\PrimitiveInterface;
use Drupal\Core\TypedData\Type\FloatInterface;
use Drupal\Core\TypedData\Type\IntegerInterface;
abstract class StorableConfigBase extends ConfigBase {
/**
* The storage used to load and save this configuration object.
*
* @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
*/
protected $typedConfigManager;
/**
* 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 $originalData = array();
/**
* Saves the configuration object.
*
* @return \Drupal\Core\Config\Config
* The configuration object.
*/
abstract public function save();
/**
* Deletes the configuration object.
*
* @return \Drupal\Core\Config\Config
* The configuration object.
*/
abstract public function delete();
/**
* Initializes a configuration object with pre-loaded data.
*
* @param array $data
* Array of loaded data for this configuration object.
*
* @return $this
* The configuration object.
*/
public function initWithData(array $data) {
$this->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;
}
}
......@@ -7,12 +7,12 @@
namespace Drupal\Core\Theme;