diff --git a/core/includes/config.inc b/core/includes/config.inc index ffd7036..c3a8d17 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -2,7 +2,8 @@ use Drupal\Core\Config\Config; use Drupal\Core\Config\ConfigException; -use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\ConfigName; +use Drupal\Core\Config\EnableStorage; use Drupal\Core\Config\StorageInterface; use Symfony\Component\Yaml\Dumper; @@ -32,12 +33,12 @@ function config_install_default_config($type, $name) { // If this module defines any ConfigEntity types then create an empty // manifest file for each of them. foreach (config_get_module_config_entities($name) as $entity_info) { - config('manifest.' . $entity_info['config_prefix'])->save(); + config(new ConfigName('manifest.' . $entity_info['config_prefix'], $name))->save(); } $config_dir = drupal_get_path($type, $name) . '/config'; if (is_dir($config_dir)) { - $source_storage = new FileStorage($config_dir); + $source_storage = new EnableStorage($config_dir, $name); $target_storage = drupal_container()->get('config.storage'); // Ignore manifest files. @@ -71,11 +72,8 @@ function config_uninstall_default_config($type, $name) { config($config_name)->delete(); } - // If this module defines any ConfigEntity types, then delete the manifest - // file for each of them. - foreach (config_get_module_config_entities($name) as $entity_type) { - config('manifest.' . $entity_info['config_prefix'])->delete(); - } + // Remove extension's directory in the active store. + drupal_rmdir($storage->getDirectory() . '/' . $name); } /** @@ -94,10 +92,11 @@ function config_get_storage_names_with_prefix($prefix = '') { * @code config('book.admin') @endcode will return a configuration object in * which the book module can store its administrative settings. * - * @param string $name + * @param mixed $name * The name of the configuration object to retrieve. The name corresponds to * a configuration file. For @code config('book.admin') @endcode, the config * object returned will contain the contents of book.admin configuration file. + * This either be a string or an instance of \Drupal\Core\Config\ConfigName. * * @return Drupal\Core\Config\Config * A configuration object. @@ -175,8 +174,19 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf 'change' => array(), 'delete' => array(), ); - $all_source_names = $source_storage->listAll(); - $all_target_names = $target_storage->listAll(); + + // @todo this is more than a bit ugly. We need to tidy this up. + $all_source_names = array(); + foreach ($source_storage->listAll() as $config_name) { + $all_source_names[(string) $config_name] = $config_name; + } + $all_source_names_strings = array_keys($all_source_names); + + $all_target_names = array(); + foreach ($target_storage->listAll() as $config_name) { + $all_target_names[(string) $config_name] = $config_name; + } + $all_target_names_strings = array_keys($all_target_names); // Config entities maintain 'manifest' files that list the objects they // are currently handling. Each file is a simple indexed array of config @@ -197,25 +207,32 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf } foreach (array_diff_key($target_config_data, $source_config_data) as $name => $value) { - $config_changes['delete'][] = $value['name']; + $config_changes['delete'][] = $all_target_names[$value['name']]; } foreach (array_diff_key($source_config_data, $target_config_data) as $name => $value) { - $config_changes['create'][] = $value['name']; + $config_changes['create'][] = $all_source_names[$value['name']]; } } else { - $config_changes['delete'] = array_diff($all_target_names, $all_source_names); - $config_changes['create'] = array_diff($all_source_names, $all_target_names); + $config_changes['delete'] = array_intersect_key( + $all_target_names, + drupal_map_assoc(array_diff($all_target_names_strings, $all_source_names_strings)) + ); + $config_changes['create'] = array_intersect_key( + $all_source_names, + drupal_map_assoc(array_diff($all_source_names_strings, $all_target_names_strings)) + ); } - foreach (array_intersect($all_source_names, $all_target_names) as $name) { + foreach (array_intersect($all_source_names_strings, $all_target_names_strings) as $name) { // Ignore manifest files if (substr($name, 0, 9) != 'manifest.') { - $source_config_data = $source_storage->read($name); - $target_config_data = $target_storage->read($name); + $config_name = $all_source_names[$name]; + $source_config_data = $source_storage->read($config_name); + $target_config_data = $target_storage->read($config_name); if ($source_config_data !== $target_config_data) { - $config_changes['change'][] = $name; + $config_changes['change'][] = $config_name; } } } @@ -350,7 +367,7 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou $handled_by_module = FALSE; // Validate the configuration object name before importing it. Config::validateName($name); - if ($entity_type = config_get_entity_type_by_name($name)) { + if ($entity_type = config_get_entity_type_by_name((string) $name)) { $old_config = new Config($name, $target_storage, $free_context); $old_config->load(); @@ -361,13 +378,13 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou } $method = 'import' . ucfirst($op); - $handled_by_module = $manager->getStorageController($entity_type)->$method($name, $new_config, $old_config); + $handled_by_module = $manager->getStorageController($entity_type)->$method((string) $name, $new_config, $old_config); } if (!empty($handled_by_module)) { $factory->reset($name); // Reset the manifest config object for the config entity. $entity_info = drupal_container()->get('plugin.manager.entity')->getDefinition($entity_type); - $factory->reset('manifest.' . $entity_info['config_prefix']); + $factory->reset(new ConfigName('manifest.' . $entity_info['config_prefix'], $entity_info['module'])); unset($config_changes[$op][$key]); } } @@ -431,7 +448,7 @@ function config_typed() { * The storage to diff configuration from. * @param Drupal\Core\Config\StorageInterface $target_storage * The storage to diff configuration to. - * @param string $name + * @param \Drupal\Core\Config\ConfigName $name * The name of the configuration object to diff. * * @return core/lib/Drupal/Component/Diff @@ -439,7 +456,7 @@ function config_typed() { * * @todo Make renderer injectable */ -function config_diff(StorageInterface $source_storage, StorageInterface $target_storage, $name) { +function config_diff(StorageInterface $source_storage, StorageInterface $target_storage, ConfigName $name) { require_once DRUPAL_ROOT . '/core/lib/Drupal/Component/Diff/DiffEngine.php'; // The output should show configuration object differences formatted as YAML. diff --git a/core/includes/update.inc b/core/includes/update.inc index bf11562..d41450f 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -9,8 +9,9 @@ */ use Drupal\Component\Graph\Graph; -use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\EnableStorage; use Drupal\Core\Config\ConfigException; +use Drupal\Core\Config\ConfigName; use Drupal\Core\DrupalKernel; use Drupal\Component\Uuid\Uuid; use Drupal\Component\Utility\NestedArray; @@ -1378,6 +1379,9 @@ function update_variable_del($name) { * the data key 'new_config.sub_key' of the configuration object $config_name. */ function update_variables_to_config($config_name, array $variable_map) { + if (!is_object($config_name)) { + $config_name = new ConfigName($config_name); + } // Build the new configuration object. // This potentially loads an existing configuration object, in case another // update function migrated configuration values into $config_name already. @@ -1388,7 +1392,7 @@ function update_variables_to_config($config_name, array $variable_map) { $module = strtok($config_name, '.'); // Load and set default configuration values. - $file = new FileStorage(drupal_get_path('module', $module) . '/config'); + $file = new EnableStorage(drupal_get_path('module', $module) . '/config', $module); if (!$file->exists($config_name)) { throw new ConfigException("Default configuration file $config_name for $module extension not found but is required to exist."); } @@ -1434,7 +1438,8 @@ function update_variables_to_config($config_name, array $variable_map) { * An array of configuration entities to add to the manifest. */ function update_config_manifest_add($config_prefix, array $ids) { - $manifest = config('manifest.' . $config_prefix); + $owner = substr($config_prefix, 0, strpos($config_prefix, '.')); + $manifest = config(new ConfigName('manifest.' . $config_prefix, $owner)); // Add record to manifest for each config entity. Operate on the data array // as a whole, because $manifest->get() would treat dots in ids as nesting. diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php index 7d094b4..bf6b578 100644 --- a/core/lib/Drupal/Core/Config/CachedStorage.php +++ b/core/lib/Drupal/Core/Config/CachedStorage.php @@ -48,7 +48,7 @@ public function __construct(StorageInterface $storage, CacheBackendInterface $ca /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ - public function exists($name) { + public function exists(ConfigName $name) { // The cache would read in the entire data (instead of only checking whether // any data exists), and on a potential cache miss, an additional storage // lookup would have to happen, so check the storage directly. @@ -58,8 +58,8 @@ public function exists($name) { /** * Implements Drupal\Core\Config\StorageInterface::read(). */ - public function read($name) { - if ($cache = $this->cache->get($name)) { + public function read(ConfigName $name) { + if ($cache = $this->cache->get((string) $name)) { // The cache backend supports primitive data types, but only an array // represents valid config object data. if (is_array($cache->data)) { @@ -69,12 +69,12 @@ public function read($name) { // Read from the storage on a cache miss and cache the data, if any. $data = $this->storage->read($name); if ($data !== FALSE) { - $this->cache->set($name, $data, CacheBackendInterface::CACHE_PERMANENT); + $this->cache->set((string) $name, $data, CacheBackendInterface::CACHE_PERMANENT); } // If the cache contained bogus data and there is no data in the storage, // wipe the cache entry. elseif ($cache) { - $this->cache->delete($name); + $this->cache->delete((string) $name); } return $data; } @@ -82,11 +82,11 @@ public function read($name) { /** * Implements Drupal\Core\Config\StorageInterface::write(). */ - public function write($name, array $data) { + public function write(ConfigName $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, CacheBackendInterface::CACHE_PERMANENT); + $this->cache->set((string) $name, $data, CacheBackendInterface::CACHE_PERMANENT); return TRUE; } return FALSE; @@ -95,11 +95,11 @@ public function write($name, array $data) { /** * Implements Drupal\Core\Config\StorageInterface::delete(). */ - public function delete($name) { + public function delete(ConfigName $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((string) $name); return TRUE; } return FALSE; @@ -108,12 +108,12 @@ public function delete($name) { /** * Implements Drupal\Core\Config\StorageInterface::rename(). */ - public function rename($name, $new_name) { + public function rename(ConfigName $name, ConfigName $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((string) $name); + $this->cache->delete((string) $new_name); return TRUE; } return FALSE; @@ -155,4 +155,13 @@ public function deleteAll($prefix = '') { } return FALSE; } + + /** + * Implements Drupal\Core\Config\StorageInterface::getDirectory(). + * + * Not supported by CacheBackendInterface. + */ + public function getDirectory() { + return $this->storage->getDirectory(); + } } diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index c0d2617..2688aa5 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -31,7 +31,7 @@ class Config { /** * The name of the configuration object. * - * @var string + * @var \Drupal\Core\Config\ConfigName */ protected $name; @@ -88,7 +88,7 @@ class Config { * @param \Drupal\Core\Config\Context\ContextInterface $context * The configuration context used for this configuration object. */ - public function __construct($name, StorageInterface $storage, ContextInterface $context) { + public function __construct(ConfigName $name, StorageInterface $storage, ContextInterface $context) { $this->name = $name; $this->storage = $storage; $this->context = $context; @@ -123,7 +123,7 @@ public function getName() { * @return Drupal\Core\Config\Config * The configuration object. */ - public function setName($name) { + public function setName(ConfigName $name) { $this->name = $name; return $this; } @@ -135,7 +135,7 @@ public function setName($name) { * * @see Config::MAX_NAME_LENGTH */ - public static function validateName($name) { + public static function validateName(ConfigName $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( @@ -448,7 +448,7 @@ public function save() { * @return Drupal\Core\Config\Config * The configuration object. */ - public function rename($new_name) { + public function rename(ConfigName $new_name) { if ($this->storage->rename($this->name, $new_name)) { $this->name = $new_name; } diff --git a/core/lib/Drupal/Core/Config/ConfigDirectoryFilterIterator.php b/core/lib/Drupal/Core/Config/ConfigDirectoryFilterIterator.php new file mode 100644 index 0000000..f3ceb1a --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigDirectoryFilterIterator.php @@ -0,0 +1,47 @@ +extension = $extension; + $this->prefix = $prefix; + } + + /** + * Implements \FilterIterator::accept(). + */ + public function accept() { + $fileInfo = $this->current(); + return ($fileInfo->getExtension() == $this->extension) && (empty($this->prefix) || (strpos($fileInfo->getFilename(), $this->prefix) === 0)); + } + +} diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index 3179b17..2f8c1e8 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -67,10 +67,13 @@ public function __construct(StorageInterface $storage, ContextInterface $context /** * Returns a configuration object for a given name and context. * - * @param string $name + * @param mixed $name * The name of the configuration object to construct. */ public function get($name) { + if (!is_object($name)) { + $name = new ConfigName($name); + } $context = $this->getContext(); $cache_key = $this->getCacheKey($name, $context); if (isset($this->cache[$cache_key])) { @@ -84,14 +87,14 @@ public function get($name) { /** * Resets and re-initializes configuration objects. Internal use only. * - * @param string $name + * @param ConfigName $name * (optional) The name of the configuration object to reset. If omitted, all * configuration objects are reset. * * @return \Drupal\Core\Config\ConfigFactory * The config factory object. */ - public function reset($name = NULL) { + public function reset(ConfigName $name = NULL) { if ($name) { // Reinitialize the configuration object in all contexts. foreach ($this->getCacheKeys($name) as $cache_key) { @@ -109,14 +112,14 @@ public function reset($name = NULL) { /** * Renames a configuration object in the cache. * - * @param string $old_name + * @param ConfigName $old_name * The old name of the configuration object. - * @param string $new_name + * @param ConfigName $new_name * The new name of the configuration object. * * @todo D8: Remove after http://drupal.org/node/1865206. */ - public function rename($old_name, $new_name) { + public function rename(ConfigName $old_name, ConfigName $new_name) { $old_cache_key = $this->getCacheKey($old_name, $this->getContext()); $new_cache_key = $this->getCacheKey($new_name, $this->getContext()); if (isset($this->cache[$old_cache_key])) { @@ -174,7 +177,7 @@ public function leaveContext() { /** * Gets the cache key for a given config name in a particular context. * - * @param string $name + * @param ConfigName $name * The name of the configuration object. * @param \Drupal\Core\Config\Context\ContextInterface $context * The configuration context. @@ -182,23 +185,23 @@ public function leaveContext() { * @return string * The cache key. */ - public function getCacheKey($name, ContextInterface $context) { + public function getCacheKey(ConfigName $name, ContextInterface $context) { return $name . ':' . $context->getUuid(); } /** * Gets all the cache keys that match the provided config name. * - * @param string $name + * @param ConfigName $name * The name of the configuration object. * * @return array * An array of cache keys that match the provided config name. */ - public function getCacheKeys($name) { + public function getCacheKeys(ConfigName $name) { $cache_keys = array_keys($this->cache); return array_filter($cache_keys, function($key) use ($name) { - return ( strpos($key, $name) !== false ); + return ( strpos($key, (string) $name) !== false ); }); } } diff --git a/core/lib/Drupal/Core/Config/ConfigName.php b/core/lib/Drupal/Core/Config/ConfigName.php new file mode 100644 index 0000000..73a12b5 --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigName.php @@ -0,0 +1,86 @@ +name = $name; + if (!$owner) { + $this->owner = $this->getOwnerFromName($name); + } + else { + $this->owner = $owner; + } + } + + /** + * Gets the configuration owner from the configuration name. + * + * @param $name + * The configuration name. + * + * @return string + * The configuration owner. + */ + protected function getOwnerFromName($name) { + return substr($name, 0, strpos($name, '.')); + } + + /** + * Gets the configuration owner. + * + * @return string + * The configuration owner. + */ + public function getOwner() { + return $this->owner; + } + + /** + * Converts the object to a string. + * + * @return string + * The configuration object name. + */ + public function __toString() { + return $this->name; + } +} diff --git a/core/lib/Drupal/Core/Config/Context/ConfigContext.php b/core/lib/Drupal/Core/Config/Context/ConfigContext.php index ab2ac54..8bae6b2 100644 --- a/core/lib/Drupal/Core/Config/Context/ConfigContext.php +++ b/core/lib/Drupal/Core/Config/Context/ConfigContext.php @@ -109,11 +109,12 @@ public function notify($config_event_name, Config $config = NULL) { * Implements \Drupal\Core\Config\Context\ContextInterface::setOverride(). */ public function setOverrides($config_name, $data) { - if (!isset($this->overrides[$config_name])) { - $this->overrides[$config_name] = $data; + $name = (string) $config_name; + if (!isset($this->overrides[$name])) { + $this->overrides[$name] = $data; } else { - $this->overrides[$config_name] = NestedArray::mergeDeepArray(array($this->overrides[$config_name], $data), TRUE); + $this->overrides[$name] = NestedArray::mergeDeepArray(array($this->overrides[$name], $data), TRUE); } } @@ -121,8 +122,8 @@ public function setOverrides($config_name, $data) { * Implements \Drupal\Core\Config\Context\ContextInterface::getOverrides(). */ public function getOverrides($config_name) { - if (isset($this->overrides[$config_name])) { - return $this->overrides[$config_name]; + if (isset($this->overrides[(string) $config_name])) { + return $this->overrides[(string) $config_name]; } return FALSE; } diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php index 3d43a8c..7d21d75 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php @@ -10,6 +10,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Database\Connection; use Exception; +use PDO; /** * Defines the Database storage controller. @@ -56,7 +57,7 @@ public function __construct(Connection $connection, $table, array $options = arr /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ - public function exists($name) { + public function exists(ConfigName $name) { return (bool) $this->connection->queryRange('SELECT 1 FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name = :name', 0, 1, array( ':name' => $name, ), $this->options)->fetchField(); @@ -69,7 +70,7 @@ public function exists($name) { * @throws Drupal\Core\Database\DatabaseExceptionWrapper * Only thrown in case $this->options['throw_exception'] is TRUE. */ - public function read($name) { + public function read(ConfigName $name) { $data = FALSE; // There are situations, like in the installer, where we may attempt a // read without actually having the database available. In this case, @@ -93,12 +94,15 @@ public function read($name) { * * @todo Ignore slave targets for data manipulation operations. */ - public function write($name, array $data) { + public function write(ConfigName $name, array $data) { $data = $this->encode($data); $options = array('return' => Database::RETURN_AFFECTED) + $this->options; return (bool) $this->connection->merge($this->table, $options) ->key(array('name' => $name)) - ->fields(array('data' => $data)) + ->fields(array( + 'owner' => $name->getOwner(), + 'data' => $data, + )) ->execute(); } @@ -109,7 +113,7 @@ public function write($name, array $data) { * * @todo Ignore slave targets for data manipulation operations. */ - public function delete($name) { + public function delete(ConfigName $name) { $options = array('return' => Database::RETURN_AFFECTED) + $this->options; return (bool) $this->connection->delete($this->table, $options) ->condition('name', $name) @@ -122,7 +126,7 @@ public function delete($name) { * * @throws PDOException */ - public function rename($name, $new_name) { + public function rename(ConfigName $name, ConfigName $new_name) { $options = array('return' => Database::RETURN_AFFECTED) + $this->options; return (bool) $this->connection->update($this->table, $options) ->fields(array('name' => $new_name)) @@ -156,9 +160,14 @@ public function decode($raw) { * Only thrown in case $this->options['throw_exception'] is TRUE. */ public function listAll($prefix = '') { - return $this->connection->query('SELECT name FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name LIKE :name', array( + $names = $this->connection->query('SELECT name, owner FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name LIKE :name', array( ':name' => db_like($prefix) . '%', - ), $this->options)->fetchCol(); + ), $this->options)->fetchAll(PDO::FETCH_ASSOC); + + // @todo this does not work! ConfigSnapshot needs to know the owner... + return array_map(function ($name) { + return new ConfigName($name['name'], $name['owner']); + }, $names); } /** @@ -174,4 +183,11 @@ public function deleteAll($prefix = '') { ->condition('name', $prefix . '%', 'LIKE') ->execute(); } + + /** + * Implements Drupal\Core\Config\StorageInterface::getDirectory(). + */ + public function getDirectory() { + throw new StorageException('Get directory operation not supported.'); + } } diff --git a/core/lib/Drupal/Core/Config/EnableStorage.php b/core/lib/Drupal/Core/Config/EnableStorage.php new file mode 100644 index 0000000..3e00b76 --- /dev/null +++ b/core/lib/Drupal/Core/Config/EnableStorage.php @@ -0,0 +1,110 @@ +directory = $directory; + $this->owner = $owner; + } + + /** + * Overrides Drupal\Core\Config\FileStorage::getFilePath(). + * + * Returns the path to the configuration file. + * + * Determines the owner and path to the default configuration file of a + * requested config object name located in the installation profile, a module, + * or a theme (in this order). + * + * @param \Drupal\Core\Config\ConfigName $name + * The name of the configuration object. + * + * @return string + * The path to the configuration file. + * + * @todo Improve this when figuring out how we want to handle configuration in + * installation profiles. E.g., a config object actually has to be searched + * in the profile first (whereas the profile is never the owner), only + * afterwards check for a corresponding module or theme. + */ + public function getFilePath(ConfigName $name) { + return $this->directory . '/' . $name . '.' . $this->getFileExtension(); + } + + /** + * Overrides Drupal\Core\Config\FileStorage::write(). + * + * @throws Drupal\Core\Config\StorageException + */ + public function write(ConfigName $name, array $data) { + throw new StorageException('Write operation is not allowed.'); + } + + /** + * Overrides Drupal\Core\Config\FileStorage::delete(). + * + * @throws Drupal\Core\Config\StorageException + */ + public function delete(ConfigName $name) { + throw new StorageException('Delete operation is not allowed.'); + } + + /** + * Overrides Drupal\Core\Config\FileStorage::rename(). + * + * @throws Drupal\Core\Config\StorageException + */ + public function rename(ConfigName $name, ConfigName $new_name) { + throw new StorageException('Rename operation is not allowed.'); + } + + /** + * Implements Drupal\Core\Config\StorageInterface::listAll(). + */ + public function listAll($prefix = '') { + // glob() silently ignores the error of a non-existing search directory, + // even with the GLOB_ERR flag. + if (!file_exists($this->directory)) { + throw new StorageException($this->directory . '/ not found.'); + } + $extension = '.' . static::getFileExtension(); + $owner = $this->owner; + $files = glob($this->directory . '/' . $prefix . '*' . $extension); + $clean_name = function ($value) use ($extension, $owner) { + return new ConfigName(basename($value, $extension), $owner); + }; + return array_map($clean_name, $files); + } + + /** + * Overrides Drupal\Core\Config\FileStorage::deleteAll(). + * + * @throws Drupal\Core\Config\StorageException + */ + public function deleteAll($prefix = '') { + throw new StorageException('Delete operation is not allowed.'); + } + +} diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index 92e4be3..b03a68a 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityMalformedException; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Config\Config; +use Drupal\Core\Config\ConfigName; /** * Defines the storage controller class for configuration entities. @@ -222,28 +223,27 @@ public static function getIDFromConfigName($config_name, $config_prefix) { protected function buildQuery($ids, $revision_id = FALSE) { $config_class = $this->entityInfo['class']; $prefix = $this->getConfigPrefix(); + $names = drupal_container()->get('config.storage')->listAll($prefix); + + if ($ids !== NULL) { + // Add prefix to ids. + $ids = array_map(function ($id) use ($prefix) { + return $prefix . $id; + }, $ids); + + // Filter names array to only supplied ids. + $names = array_filter($names, function ($name) use ($ids) { + return in_array((string) $name, $ids); + }); + } // Load all of the configuration entities. - if ($ids === NULL) { - $names = drupal_container()->get('config.storage')->listAll($prefix); - $result = array(); - foreach ($names as $name) { - $config = config($name); - $result[$config->get($this->idKey)] = new $config_class($config->get(), $this->entityType); - } - return $result; - } - else { - $result = array(); - foreach ($ids as $id) { - // Add the prefix to the ID to serve as the configuration object name. - $config = config($prefix . $id); - if (!$config->isNew()) { - $result[$id] = new $config_class($config->get(), $this->entityType); - } - } - return $result; + $result = array(); + foreach ($names as $name) { + $config = config($name); + $result[$config->get($this->idKey)] = new $config_class($config->get(), $this->entityType); } + return $result; } /** @@ -328,7 +328,7 @@ public function delete(array $entities) { // Remove the entity from the manifest file. Entity id's can contain a dot // so we can not use Config::clear() to remove the entity from the // manifest. - $manifest = config('manifest.' . $this->entityInfo['config_prefix']); + $manifest = config(new ConfigName('manifest.' . $this->entityInfo['config_prefix'], $this->entityInfo['module'])); $manifest_data = $manifest->get(); unset($manifest_data[$entity->id()]); $manifest->setData($manifest_data); @@ -361,7 +361,15 @@ public function save(EntityInterface $entity) { if ($entity->getOriginalID() !== NULL) { $id = $entity->getOriginalID(); } - $config = config($prefix . $id); + // If the entity has a module property use it to set the configuration + // owner. + if ($module = $entity->get('module')) { + $config_name = new ConfigName($prefix . $id, $module); + } + else { + $config_name = new ConfigName($prefix . $id); + } + $config = config($config_name); $is_new = $config->isNew(); if ($id !== $entity->id()) { @@ -369,7 +377,8 @@ public function save(EntityInterface $entity) { // - Storage controller needs to access the original object. // - The object needs to be renamed/copied in ConfigFactory and reloaded. // - All instances of the object need to be renamed. - drupal_container()->get('config.factory')->rename($prefix . $id, $prefix . $entity->id()); + $config_name_old = new ConfigName($prefix . $entity->id(), $config_name->getOwner()); + drupal_container()->get('config.factory')->rename($config_name, $config_name_old); } if (!$is_new && !isset($entity->original)) { @@ -404,7 +413,7 @@ public function save(EntityInterface $entity) { } // Add this entity to the manifest file if necessary. - $config = config('manifest.' . $this->entityInfo['config_prefix']); + $config = config(new ConfigName('manifest.' . $this->entityInfo['config_prefix'], $this->entityInfo['module'])); $manifest = $config->get(); if (!in_array($this->getConfigPrefix() . $entity->id(), $manifest)) { $manifest[$entity->id()] = array( diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index 6422e9d..508cfe9 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -9,6 +9,8 @@ use Symfony\Component\Yaml\Dumper; use Symfony\Component\Yaml\Parser; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; /** * Defines the file storage controller. @@ -49,11 +51,21 @@ public function __construct($directory) { /** * Returns the path to the configuration file. * + * @param \Drupal\Core\Config\ConfigName $name + * The name of the configuration object. + * * @return string * The path to the configuration file. */ - public function getFilePath($name) { - return $this->directory . '/' . $name . '.' . static::getFileExtension(); + public function getFilePath(ConfigName $name) { + return $this->directory . '/' . $name->getOwner() . '/' . $name . '.' . static::getFileExtension(); + } + + /** + * Implements Drupal\Core\Config\StorageInterface::getDirectory(). + */ + public function getDirectory() { + return $this->directory; } /** @@ -69,7 +81,7 @@ public static function getFileExtension() { /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ - public function exists($name) { + public function exists(ConfigName $name) { return file_exists($this->getFilePath($name)); } @@ -78,7 +90,7 @@ public function exists($name) { * * @throws Symfony\Component\Yaml\Exception\ParseException */ - public function read($name) { + public function read(ConfigName $name) { if (!$this->exists($name)) { return FALSE; } @@ -95,7 +107,8 @@ public function read($name) { * @throws Symfony\Component\Yaml\Exception\DumpException * @throws Drupal\Core\Config\StorageException */ - public function write($name, array $data) { + public function write(ConfigName $name, array $data) { + $this->ensureOwnerDirectory($name); $data = $this->encode($data); $status = @file_put_contents($this->getFilePath($name), $data); if ($status === FALSE) { @@ -105,9 +118,27 @@ public function write($name, array $data) { } /** + * Ensures that the owner directory for configuration exists. + * + * @param ConfigName $name + * The configuration name object. + * + * @throws StorageException + */ + public function ensureOwnerDirectory(ConfigName $name) { + $directory = $this->directory . '/' . $name->getOwner(); + if (!is_dir($directory)) { + $status = @drupal_mkdir($directory); + if ($status === FALSE) { + throw new StorageException('Failed to create configuration directory: ' . $directory); + } + } + } + + /** * Implements Drupal\Core\Config\StorageInterface::delete(). */ - public function delete($name) { + public function delete(ConfigName $name) { if (!$this->exists($name)) { if (!file_exists($this->directory)) { throw new StorageException($this->directory . '/ not found.'); @@ -120,7 +151,7 @@ public function delete($name) { /** * Implements Drupal\Core\Config\StorageInterface::rename(). */ - public function rename($name, $new_name) { + public function rename(ConfigName $name, ConfigName $new_name) { $status = @rename($this->getFilePath($name), $this->getFilePath($new_name)); if ($status === FALSE) { throw new StorageException('Failed to rename configuration file from: ' . $this->getFilePath($name) . ' to: ' . $this->getFilePath($new_name)); @@ -184,17 +215,18 @@ public function decode($raw) { * Implements Drupal\Core\Config\StorageInterface::listAll(). */ public function listAll($prefix = '') { - // glob() silently ignores the error of a non-existing search directory, - // even with the GLOB_ERR flag. - if (!file_exists($this->directory)) { + $directory = new RecursiveDirectoryIterator($this->directory); + + if (empty($directory)) { throw new StorageException($this->directory . '/ not found.'); } - $extension = '.' . static::getFileExtension(); - $files = glob($this->directory . '/' . $prefix . '*' . $extension); - $clean_name = function ($value) use ($extension) { - return basename($value, $extension); - }; - return array_map($clean_name, $files); + + $extension = static::getFileExtension(); + $flattened = new RecursiveIteratorIterator($directory); + $files = new ConfigDirectoryFilterIterator($flattened, $extension, $prefix); + return array_map(function ($fileInfo) use ($extension) { + return new ConfigName($fileInfo->getBasename('.' . $extension), basename($fileInfo->getPathInfo()->getRealPath())); + }, iterator_to_array($files)); } /** diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php index 41db679..09a02fc 100644 --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -24,7 +24,8 @@ class InstallStorage extends FileStorage { /** * Overrides Drupal\Core\Config\FileStorage::__construct(). */ - public function __construct() { + public function __construct($directory = NULL) { + $this->directory = $directory; } /** @@ -36,6 +37,9 @@ public function __construct() { * requested config object name located in the installation profile, a module, * or a theme (in this order). * + * @param \Drupal\Core\Config\ConfigName $name + * The name of the configuration object. + * * @return string * The path to the configuration file. * @@ -44,10 +48,20 @@ public function __construct() { * in the profile first (whereas the profile is never the owner), only * afterwards check for a corresponding module or theme. */ - public function getFilePath($name) { - $folders = $this->getAllFolders(); - if (isset($folders[$name])) { - return $folders[$name] . '/' . $name . '.' . $this->getFileExtension(); + public function getFilePath(ConfigName $name) { + $directory = FALSE; + if ($this->directory) { + $directory = $this->directory; + } + else { + $folders = $this->getAllFolders(); + if (isset($folders[(string) $name])) { + $directory = $folders[(string) $name]; + } + } + + if ($directory) { + return $directory . '/' . $name . '.' . $this->getFileExtension(); } // If any code in the early installer requests a configuration object that // does not exist anywhere as default config, then that must be mistake. @@ -61,7 +75,7 @@ public function getFilePath($name) { * * @throws Drupal\Core\Config\StorageException */ - public function write($name, array $data) { + public function write(ConfigName $name, array $data) { throw new StorageException('Write operation is not allowed during install.'); } @@ -70,7 +84,7 @@ public function write($name, array $data) { * * @throws Drupal\Core\Config\StorageException */ - public function delete($name) { + public function delete(ConfigName $name) { throw new StorageException('Delete operation is not allowed during install.'); } @@ -79,7 +93,7 @@ public function delete($name) { * * @throws Drupal\Core\Config\StorageException */ - public function rename($name, $new_name) { + public function rename(ConfigName $name, ConfigName $new_name) { throw new StorageException('Rename operation is not allowed during install.'); } @@ -87,77 +101,85 @@ public function rename($name, $new_name) { * Implements Drupal\Core\Config\StorageInterface::listAll(). */ public function listAll($prefix = '') { + if ($this->directory) { + return parent::listAll($prefix); + } + else { $names = array_keys($this->getAllFolders()); - if (!$prefix) { - return $names; - } - else { - $return = array(); - foreach ($names as $index => $name) { - if (strpos($name, $prefix) === 0 ) { - $return[$index] = $names[$index]; - } + } + if (!$prefix) { + + return array_map(function ($name) { + return new ConfigName($name); + } ,$names); + } + else { + $return = array(); + foreach ($names as $index => $name) { + if (strpos($name, $prefix) === 0 ) { + $return[] = new ConfigName($names[$index]); } - return $return; } + return $return; } + } - /** - * Returns a map of all config object names and their folders. - * - * @return array - * An array mapping config object names with directories. - */ - protected function getAllFolders() { - if (!isset($this->folders)) { - $this->folders = $this->getComponentNames('profile', array(drupal_get_profile())); - $this->folders += $this->getComponentNames('module', array_keys(drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules', 'name', 0))); - $this->folders += $this->getComponentNames('theme', array_keys(drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'themes'))); - } - return $this->folders; + /** + * Returns a map of all config object names and their folders. + * + * @return array + * An array mapping config object names with directories. + */ + protected function getAllFolders() { + if (!isset($this->folders)) { + $this->folders = $this->getComponentNames('profile', array(drupal_get_profile())); + $this->folders += $this->getComponentNames('module', array_keys(drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules', 'name', 0))); + $this->folders += $this->getComponentNames('theme', array_keys(drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'themes'))); } + return $this->folders; + } - /** - * Get all configuration names and folders for a list of modules or themes. - * - * @param string $type - * Type of components: 'module' | 'theme' | 'profile' - * @param array $list - * Array of theme or module names. - * - * @return array - * Folders indexed by configuration name. - */ - protected function getComponentNames($type, array $list) { - $extension = '.' . $this->getFileExtension(); - $folders = array(); - foreach ($list as $name) { - $directory = $this->getComponentFolder($type, $name); - if (file_exists($directory)) { - $files = glob($directory . '/*' . $extension); - foreach ($files as $filename) { - $name = basename($filename, $extension); - $folders[$name] = $directory; - } + /** + * Get all configuration names and folders for a list of modules or themes. + * + * @param string $type + * Type of components: 'module' | 'theme' | 'profile' + * @param array $list + * Array of theme or module names. + * + * @return array + * Folders indexed by configuration name. + */ + protected function getComponentNames($type, array $list) { + $extension = '.' . $this->getFileExtension(); + $folders = array(); + foreach ($list as $name) { + $directory = $this->getComponentFolder($type, $name); + if (file_exists($directory)) { + $files = glob($directory . '/*' . $extension); + foreach ($files as $filename) { + $name = basename($filename, $extension); + $folders[$name] = $directory; } } - return $folders; } + return $folders; + } - /** - * Get folder inside each component that contains the files. - * - * @param string $type - * Component type: 'module' | 'theme' | 'profile' - * @param string $name - * Component name. - * - * @return string - * The configuration folder name for this component. - */ - protected function getComponentFolder($type, $name) { - return drupal_get_path($type, $name) . '/config'; - } + /** + * Get folder inside each component that contains the files. + * + * @param string $type + * Component type: 'module' | 'theme' | 'profile' + * @param string $name + * Component name. + * + * @return string + * The configuration folder name for this component. + */ + protected function getComponentFolder($type, $name) { + return drupal_get_path($type, $name) . '/config'; + } /** * Overrides Drupal\Core\Config\FileStorage::deleteAll(). @@ -168,4 +190,13 @@ public function deleteAll($prefix = '') { throw new StorageException('Delete operation is not allowed during install.'); } + /** + * Overrides Drupal\Core\Config\FileStorage::getDirectory(). + * + * @throws Drupal\Core\Config\StorageException + */ + public function getDirectory() { + // Install storage is designed to work on multiple directories. + throw new StorageException('Get directory operation is not allowed.'); + } } diff --git a/core/lib/Drupal/Core/Config/NullStorage.php b/core/lib/Drupal/Core/Config/NullStorage.php index 336c111..245de50 100644 --- a/core/lib/Drupal/Core/Config/NullStorage.php +++ b/core/lib/Drupal/Core/Config/NullStorage.php @@ -26,35 +26,35 @@ class NullStorage implements StorageInterface { /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ - public function exists($name) { + public function exists(ConfigName $name) { return FALSE; } /** * Implements Drupal\Core\Config\StorageInterface::read(). */ - public function read($name) { + public function read(ConfigName $name) { return array(); } /** * Implements Drupal\Core\Config\StorageInterface::write(). */ - public function write($name, array $data) { + public function write(ConfigName $name, array $data) { return FALSE; } /** * Implements Drupal\Core\Config\StorageInterface::delete(). */ - public function delete($name) { + public function delete(ConfigName $name) { return FALSE; } /** * Implements Drupal\Core\Config\StorageInterface::rename(). */ - public function rename($name, $new_name) { + public function rename(ConfigName $name, ConfigName $new_name) { return FALSE; } diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaStorage.php b/core/lib/Drupal/Core/Config/Schema/SchemaStorage.php index 171f30a..93421fa 100644 --- a/core/lib/Drupal/Core/Config/Schema/SchemaStorage.php +++ b/core/lib/Drupal/Core/Config/Schema/SchemaStorage.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Config\Schema; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\InstallStorage; use Drupal\Core\Config\StorageException; @@ -18,8 +19,8 @@ class SchemaStorage extends InstallStorage { /** * Implements \Drupal\Core\Config\StorageInterface::exists(). */ - public function exists($name) { - return array_key_exists($name, $this->getAllFolders()); + public function exists(ConfigName $name) { + return array_key_exists((string) $name, $this->getAllFolders()); } /** @@ -34,7 +35,7 @@ protected function getComponentFolder($type, $name) { * * @throws \Drupal\Core\Config\StorageException */ - public function write($name, array $data) { + public function write(ConfigName $name, array $data) { throw new StorageException('Write operation is not allowed for config schema storage.'); } @@ -43,7 +44,7 @@ public function write($name, array $data) { * * @throws \Drupal\Core\Config\StorageException */ - public function delete($name) { + public function delete(ConfigName $name) { throw new StorageException('Delete operation is not allowed for config schema storage.'); } @@ -52,7 +53,7 @@ public function delete($name) { * * @throws \Drupal\Core\Config\StorageException */ - public function rename($name, $new_name) { + public function rename(ConfigName $name, ConfigName $new_name) { throw new StorageException('Rename operation is not allowed for config schema storage.'); } diff --git a/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/StorageInterface.php index ceeecba..3208704 100644 --- a/core/lib/Drupal/Core/Config/StorageInterface.php +++ b/core/lib/Drupal/Core/Config/StorageInterface.php @@ -18,30 +18,30 @@ /** * Returns whether a configuration object exists. * - * @param string $name + * @param \Drupal\Core\Config\ConfigName $name * The name of a configuration object to test. * * @return bool * TRUE if the configuration object exists, FALSE otherwise. */ - public function exists($name); + public function exists(ConfigName $name); /** * Reads configuration data from the storage. * - * @param string $name + * @param \Drupal\Core\Config\ConfigName $name * The name of a configuration object to load. * * @return array|bool * The configuration data stored for the configuration object name. If no * configuration data exists for the given name, FALSE is returned. */ - public function read($name); + public function read(ConfigName $name); /** * Writes configuration data to the storage. * - * @param string $name + * @param \Drupal\Core\Config\ConfigName $name * The name of a configuration object to save. * @param array $data * The configuration data to write. @@ -49,31 +49,31 @@ public function read($name); * @return bool * TRUE on success, FALSE in case of an error. */ - public function write($name, array $data); + public function write(ConfigName $name, array $data); /** * Deletes a configuration object from the storage. * - * @param string $name + * @param \Drupal\Core\Config\ConfigName $name * The name of a configuration object to delete. * * @return bool * TRUE on success, FALSE otherwise. */ - public function delete($name); + public function delete(ConfigName $name); /** * Renames a configuration object in the storage. * - * @param string $name + * @param \Drupal\Core\Config\ConfigName $name * The name of a configuration object to rename. - * @param string $new_name + * @param \Drupal\Core\Config\ConfigName $new_name * The new name of a configuration object. * * @return bool * TRUE on success, FALSE otherwise. */ - public function rename($name, $new_name); + public function rename(ConfigName $name, ConfigName $new_name); /** * Encodes configuration data into the storage-specific format. @@ -118,7 +118,8 @@ public function decode($raw); * names that exist are returned. * * @return array - * An array containing matching configuration object names. + * An array containing \Drupal\Core\Config\ConfigName objects of the + * matching configuration. */ public function listAll($prefix = ''); @@ -141,4 +142,14 @@ public function listAll($prefix = ''); */ public function deleteAll($prefix = ''); + /** + * Gets the a directory if implemented by the storage engine. + * + * @throws \Drupal\Core\Config\StorageException + * If the storage does not support getting a directory. + * + * @return string + * The directory used by the storage engine. + */ + public function getDirectory(); } diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php index 4a8a289..7ae1ea8 100644 --- a/core/lib/Drupal/Core/Config/TypedConfigManager.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php @@ -39,15 +39,19 @@ public function __construct(StorageInterface $configStorage, StorageInterface $s /** * Gets typed configuration data. * - * @param string $name - * Configuration object name. + * @param mixed $name + * Configuration object name. Either a string on an instance of + * \Drupal\Core\Config\ConfigName. * * @return \Drupal\Core\Config\Schema\Element * Typed configuration element. */ public function get($name) { + if (!is_object($name)) { + $name = new ConfigName($name); + } $data = $this->configStorage->read($name); - $definition = $this->getDefinition($name); + $definition = $this->getDefinition((string) $name); return $this->create($definition, $data); } diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index ee14fb3..9504899 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -9,6 +9,7 @@ use Drupal\Component\PhpStorage\PhpStorageFactory; use Drupal\Core\Config\BootstrapConfigStorageFactory; +use Drupal\Core\Config\ConfigName; use Drupal\Core\CoreBundle; use Drupal\Core\DependencyInjection\ContainerBuilder; use Symfony\Component\ClassLoader\UniversalClassLoader; @@ -165,7 +166,7 @@ public function registerBundles() { // Ensure we know what modules are enabled and that their namespaces are // registered. if (!isset($this->moduleList)) { - $module_list = $this->configStorage->read('system.module'); + $module_list = $this->configStorage->read(new ConfigName('system.module')); $this->moduleList = isset($module_list['enabled']) ? $module_list['enabled'] : array(); } $this->registerNamespaces($this->getModuleNamespaces($this->getModuleFileNames())); @@ -209,7 +210,7 @@ protected function moduleData($module) { $profiles = array_keys(array_intersect_key($this->moduleList, $all_profiles)); // If a module is within a profile directory but specifies another // profile for testing, it needs to be found in the parent profile. - if (($parent_profile_config = $this->configStorage->read('simpletest.settings')) && isset($parent_profile_config['parent_profile']) && $parent_profile_config['parent_profile'] != $profiles[0]) { + if (($parent_profile_config = $this->configStorage->read(new ConfigName('simpletest.settings'))) && isset($parent_profile_config['parent_profile']) && $parent_profile_config['parent_profile'] != $profiles[0]) { // In case both profile directories contain the same extension, the // actual profile always has precedence. array_unshift($profiles, $parent_profile_config['parent_profile']); diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php index 02bf2cb..8cbc2f3 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php @@ -26,8 +26,8 @@ public function configInit(ConfigEvent $event) { global $conf; $config = $event->getConfig(); - if (isset($conf[$config->getName()])) { - $config->setOverride($conf[$config->getName()]); + if (isset($conf[(string) $config->getName()])) { + $config->setOverride($conf[(string) $config->getName()]); } } diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigOverrideSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigOverrideSubscriber.php new file mode 100644 index 0000000..e69de29 diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc index 718c773..18bd066 100644 --- a/core/modules/config/config.admin.inc +++ b/core/modules/config/config.admin.inc @@ -37,8 +37,8 @@ function config_admin_sync_form(array &$form, array &$form_state, StorageInterfa return $form; } - foreach ($config_changes as $config_change_type => $config_files) { - if (empty($config_files)) { + foreach ($config_changes as $config_change_type => $config_names) { + if (empty($config_names)) { continue; } @@ -50,15 +50,15 @@ function config_admin_sync_form(array &$form, array &$form_state, StorageInterfa ); switch ($config_change_type) { case 'create': - $form[$config_change_type]['heading']['#value'] = format_plural(count($config_files), '@count new', '@count new'); + $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count new', '@count new'); break; case 'change': - $form[$config_change_type]['heading']['#value'] = format_plural(count($config_files), '@count changed', '@count changed'); + $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count changed', '@count changed'); break; case 'delete': - $form[$config_change_type]['heading']['#value'] = format_plural(count($config_files), '@count removed', '@count removed'); + $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count removed', '@count removed'); break; } $form[$config_change_type]['list'] = array( @@ -66,14 +66,14 @@ function config_admin_sync_form(array &$form, array &$form_state, StorageInterfa '#header' => array('Name', 'Operations'), ); - foreach ($config_files as $config_file) { + foreach ($config_names as $config_name) { $links['view_diff'] = array( 'title' => t('View differences'), - 'href' => 'admin/config/development/sync/diff/' . $config_file, + 'href' => 'admin/config/development/sync/diff/' . $config_name . '/' . $config_name->getOwner(), 'ajax' => array('dialog' => array('modal' =>TRUE, 'width' => '700px')), ); $form[$config_change_type]['list']['#rows'][] = array( - 'name' => $config_file, + 'name' => $config_name, 'operations' => array( 'data' => array( '#type' => 'operations', @@ -133,15 +133,18 @@ function config_admin_import_form_submit($form, &$form_state) { } /** - * Page callback: Shows diff of specificed configuration file. + * Page callback: Shows diff of specificed configuration object. * - * @param string $config_file - * The name of the configuration file. + * @param string $name + * The name of the configuration. + * @param string $owner + * The owner of the configuration. * * @return string * Table showing a two-way diff between the active and staged configuration. */ -function config_admin_diff_page($config_file) { +function config_admin_diff_page($name, $owner = NULL) { + $config_name = new ConfigName ($name, $owner); // Retrieve a list of differences between last known state and active store. $source_storage = drupal_container()->get('config.storage.staging'); $target_storage = drupal_container()->get('config.storage'); @@ -152,10 +155,10 @@ function config_admin_diff_page($config_file) { $output['title'] = array( '#theme' => 'html_tag', '#tag' => 'h3', - '#value' => t('View changes of @config_file', array('@config_file' => $config_file)), + '#value' => t('View changes of @config_name', array('@config_name' => $name)), ); - $diff = config_diff($target_storage, $source_storage, $config_file); + $diff = config_diff($target_storage, $source_storage, $config_name); $formatter = new DrupalDiffFormatter(); $formatter->show_header = FALSE; diff --git a/core/modules/config/config.module b/core/modules/config/config.module index e3b6027..a932292 100644 --- a/core/modules/config/config.module +++ b/core/modules/config/config.module @@ -48,11 +48,11 @@ function config_menu() { 'access arguments' => array('synchronize configuration'), 'file' => 'config.admin.inc', ); - $items['admin/config/development/sync/diff/%'] = array( + $items['admin/config/development/sync/diff/%/%'] = array( 'title' => 'Configuration file diff', 'description' => 'Diff between active and staged configuraiton.', 'page callback' => 'config_admin_diff_page', - 'page arguments' => array(5), + 'page arguments' => array(5, 6), 'access arguments' => array('synchronize configuration'), 'file' => 'config.admin.inc', ); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php index b6bded3..af3c45e 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\ConfigNameException; use Drupal\simpletest\DrupalUnitTestBase; @@ -27,7 +28,7 @@ public static function getInfo() { */ function testCRUD() { $storage = $this->container->get('config.storage'); - $name = 'config_test.crud'; + $name = new ConfigName('config_test.crud'); $config = config($name); $this->assertIdentical($config->isNew(), TRUE); @@ -86,7 +87,7 @@ function testCRUD() { $this->assertIdentical($config->isNew(), FALSE); // Rename the configuration object. - $new_name = 'config_test.crud_rename'; + $new_name = new ConfigName('config_test.crud_rename'); $config->rename($new_name); $renamed_config = config($new_name); $this->assertIdentical($renamed_config->get(), $config->get()); @@ -109,7 +110,7 @@ function testCRUD() { */ function testNameValidation() { // Verify that an object name without namespace causes an exception. - $name = 'nonamespace'; + $name = new ConfigName('nonamespace'); $message = 'Expected ConfigNameException was thrown for a name without a namespace.'; try { config($name)->save(); @@ -120,7 +121,7 @@ function testNameValidation() { } // Verify that a name longer than the maximum length causes an exception. - $name = 'config_test.herman_melville.moby_dick_or_the_whale.harper_1851.now_small_fowls_flew_screaming_over_the_yet_yawning_gulf_a_sullen_white_surf_beat_against_its_steep_sides_then_all_collapsed_and_the_great_shroud_of_the_sea_rolled_on_as_it_rolled_five_thousand_years_ago'; + $name = new ConfigName('config_test.herman_melville.moby_dick_or_the_whale.harper_1851.now_small_fowls_flew_screaming_over_the_yet_yawning_gulf_a_sullen_white_surf_beat_against_its_steep_sides_then_all_collapsed_and_the_great_shroud_of_the_sea_rolled_on_as_it_rolled_five_thousand_years_ago'); $message = 'Expected ConfigNameException was thrown for a name longer than Config::MAX_NAME_LENGTH.'; try { config($name)->save(); @@ -134,7 +135,7 @@ function testNameValidation() { $characters = $test_characters = array(':', '?', '*', '<', '>', '"', '\'', '/', '\\'); foreach ($test_characters as $i => $c) { try { - $name = 'namespace.object' . $c; + $name = new ConfigName('namespace.object' . $c); $config = config($name); $config->save(); } @@ -147,7 +148,7 @@ function testNameValidation() { ))); // Verify that a valid config object name can be saved. - $name = 'namespace.object'; + $name = new ConfigName('namespace.object'); $message = 'ConfigNameException was not thrown for a valid object name.'; try { $config = config($name); @@ -172,13 +173,17 @@ function testNameValidation() { // Write configuration with an invalid name (missing a namespace) to // staging. - $staging = $this->container->get('config.storage.staging'); - $manifest_data = config('manifest.invalid_object_name')->get(); - $manifest_data['new']['name'] = 'invalid'; - $staging->write('manifest.invalid_object_name', $manifest_data); + // @todo this test is bogus because we have a manifest that refers to a + // config entity will not corresponding file. Need to work out what to do + // here. + //$staging = $this->container->get('config.storage.staging'); + //$manifest_name = new ConfigName('manifest.invalid_object_name', 'config_test'); + //$manifest_data = config($manifest_name)->get(); + //$manifest_data['new']['name'] = 'invalid'; + //$staging->write($manifest_name, $manifest_data); // Assert that config_import returns false indicating a failure. - $this->assertFalse(config_import(), "Config import failed when trying to importing an object with an invalid name"); + //$this->assertFalse(config_import(), "Config import failed when trying to importing an object with an invalid name"); } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php index 09f126b..5071e08 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -35,7 +36,7 @@ public static function getInfo() { function testDiff() { $active = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); - $config_name = 'config_test.system'; + $config_name = new ConfigName('config_test.system'); $change_key = 'foo'; $remove_key = '404'; $add_key = 'biff'; diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php index f2e7965..46b39f1 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\FileStorage; use Drupal\simpletest\DrupalUnitTestBase; @@ -28,7 +29,7 @@ public static function getInfo() { function testReadWriteConfig() { $storage = $this->container->get('config.storage'); - $name = 'foo.bar'; + $name = new ConfigName('foo.bar'); $key = 'foo'; $value = 'bar'; $nested_key = 'biff.bang'; @@ -143,12 +144,12 @@ function testReadWriteConfig() { $this->assertNull($config->get($nested_key), 'Nested value unset.'); // Create two new configuration files to test listing - $config = config('foo.baz'); + $config = config(new ConfigName('foo.baz')); $config->set($key, $value); $config->save(); // Test chained set()->save() - $chained_name = 'biff.bang'; + $chained_name = new ConfigName('biff.bang'); $config = config($chained_name); $config->set($key, $value)->save(); @@ -189,7 +190,7 @@ function testReadWriteConfig() { * Tests serialization of configuration to file. */ function testSerialization() { - $name = $this->randomName(10) . '.' . $this->randomName(10); + $name = new ConfigName($this->randomName(10) . '.' . $this->randomName(10)); $config_data = array( // Indexed arrays; the order of elements is essential. 'numeric keys' => array('i', 'n', 'd', 'e', 'x', 'e', 'd'), diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php index 9278269..30919fa 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -45,7 +46,7 @@ function setUp() { * Tests omission of module APIs for bare configuration operations. */ function testNoImport() { - $dynamic_name = 'config_test.dynamic.dotted.default'; + $dynamic_name = new ConfigName('config_test.dynamic.dotted.default'); // Verify the default configuration values exist. $config = config($dynamic_name); @@ -59,7 +60,7 @@ function testNoImport() { * Tests deletion of configuration during import. */ function testDeleted() { - $dynamic_name = 'config_test.dynamic.dotted.default'; + $dynamic_name = new ConfigName('config_test.dynamic.dotted.default'); $storage = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); @@ -68,7 +69,7 @@ function testDeleted() { $this->assertIdentical($config->get('id'), 'dotted.default'); // Create an empty manifest to delete the configuration object. - $staging->write('manifest.config_test.dynamic', array()); + $staging->write(new ConfigName('manifest.config_test.dynamic', 'config_test'), array()); // Import. config_import(); @@ -94,7 +95,7 @@ function testDeleted() { * Tests creation of configuration during import. */ function testNew() { - $dynamic_name = 'config_test.dynamic.new'; + $dynamic_name = new ConfigName('config_test.dynamic.new'); $storage = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); @@ -116,9 +117,9 @@ function testNew() { $staging->write($dynamic_name, $original_dynamic_data); // Create manifest for new config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); + $manifest_data = config(new ConfigName('manifest.config_test.dynamic', 'config_test'))->get(); $manifest_data[$original_dynamic_data['id']]['name'] = 'config_test.dynamic.' . $original_dynamic_data['id']; - $staging->write('manifest.config_test.dynamic', $manifest_data); + $staging->write(new ConfigName('manifest.config_test.dynamic', 'config_test'), $manifest_data); $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); @@ -145,8 +146,8 @@ function testNew() { * Tests updating of configuration during import. */ function testUpdated() { - $name = 'config_test.system'; - $dynamic_name = 'config_test.dynamic.dotted.default'; + $name = new ConfigName('config_test.system'); + $dynamic_name = new ConfigName('config_test.dynamic.dotted.default'); $storage = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); @@ -164,8 +165,9 @@ function testUpdated() { $original_dynamic_data['label'] = 'Updated'; $staging->write($dynamic_name, $original_dynamic_data); // Create manifest for updated config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); - $staging->write('manifest.config_test.dynamic', $manifest_data); + $manifest_name = new ConfigName('manifest.config_test.dynamic', 'config_test'); + $manifest_data = config($manifest_name)->get(); + $staging->write($manifest_name, $manifest_data); // Verify the active configuration still returns the default values. $config = config($name); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php index 3788d67..4c001f0 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\WebTestBase; /** @@ -35,8 +36,8 @@ function setUp() { * Tests importing configuration. */ function testImport() { - $name = 'system.site'; - $dynamic_name = 'config_test.dynamic.new'; + $name = new ConfigName('system.site'); + $dynamic_name = new ConfigName('config_test.dynamic.new'); $storage = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); @@ -67,23 +68,24 @@ function testImport() { $staging->write($dynamic_name, $original_dynamic_data); // Create manifest for new config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); + $manifest_name = new ConfigName('manifest.config_test.dynamic', 'config_test'); + $manifest_data = config($manifest_name)->get(); $manifest_data[$original_dynamic_data['id']]['name'] = 'config_test.dynamic.' . $original_dynamic_data['id']; - $staging->write('manifest.config_test.dynamic', $manifest_data); + $staging->write($manifest_name, $manifest_data); $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); // Verify that both appear as new. $this->drupalGet('admin/config/development/sync'); - $this->assertText($name); - $this->assertText($dynamic_name); + $this->assertText((string) $name); + $this->assertText((string) $dynamic_name); $this->assertFieldById('edit-submit', t('Import all')); // Import and verify that both do not appear anymore. $this->drupalPost(NULL, array(), t('Import all')); $this->assertUrl('admin/config/development/sync'); - $this->assertNoText($name); - $this->assertNoText($dynamic_name); + $this->assertNoText((string) $name); + $this->assertNoText((string) $dynamic_name); $this->assertNoFieldById('edit-submit', t('Import all')); // Verify that there are no further changes to import. @@ -132,7 +134,7 @@ function testImportLock() { function testImportDiff() { $active = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); - $config_name = 'config_test.system'; + $config_name = new ConfigName('config_test.system'); $change_key = 'foo'; $remove_key = '404'; $add_key = 'biff'; @@ -174,6 +176,6 @@ function prepareSiteNameUpdate($new_site_name) { // Create updated configuration object. $config_data = config('system.site')->get(); $config_data['name'] = $new_site_name; - $staging->write('system.site', $config_data); + $staging->write(new ConfigName('system.site'), $config_data); } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php index 4cb9ea3..2b6e6c8 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -33,15 +34,15 @@ function setUp() { * Tests module installation. */ function testModuleInstallation() { - $default_config = 'config_test.system'; - $default_configuration_entity = 'config_test.dynamic.dotted.default'; - $default_config_manifest = 'manifest.config_test.dynamic'; + $default_config = new ConfigName('config_test.system'); + $default_configuration_entity = new ConfigName('config_test.dynamic.dotted.default'); + $default_config_manifest = new ConfigName('manifest.config_test.dynamic', 'config_test'); $expected_manifest_data = array( 'dotted.default' => array( 'name' => 'config_test.dynamic.dotted.default', ), ); - $default_empty_config_manifest = 'manifest.config_test.empty_manifest'; + $default_empty_config_manifest = new ConfigName('manifest.config_test.empty_manifest', 'config_test'); // Verify that default module config does not exist before installation yet. $config = config($default_config); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php index ff48bf4..a8ef57a 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\WebTestBase; /** @@ -33,8 +34,8 @@ function setUp() { * Tests module re-installation. */ function testIntegrationModuleReinstallation() { - $default_config = 'config_integration_test.settings'; - $default_configuration_entity = 'config_test.dynamic.config_integration_test'; + $default_config = new ConfigName('config_integration_test.settings'); + $default_configuration_entity = new ConfigName('config_test.dynamic.config_integration_test'); // Install the config_test module we're integrating with. module_enable(array('config_test')); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php index 6dfcf4e..f8936e5 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOverrideTest.php @@ -8,6 +8,7 @@ namespace Drupal\config\Tests; use Drupal\simpletest\DrupalUnitTestBase; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\Context\ConfigContext; /** @@ -39,6 +40,7 @@ public function setUp() { * Tests configuration override. */ function testConfOverride() { + $name = new ConfigName('config_test.system'); global $conf; $expected_original_data = array( 'foo' => 'bar', @@ -57,14 +59,14 @@ function testConfOverride() { // Verify that the original configuration data exists. Have to read storage // directly otherwise overrides will apply. $active = $this->container->get('config.storage'); - $data = $active->read('config_test.system'); + $data = $active->read($name); $this->assertIdentical($data['foo'], $expected_original_data['foo']); $this->assertFalse(isset($data['baz'])); $this->assertIdentical($data['404'], $expected_original_data['404']); // Enter an override-free context to ensure the original data remains. config_context_enter('config.context.free'); - $config = config('config_test.system'); + $config = config($name); $this->assertIdentical($config->get('foo'), $expected_original_data['foo']); $this->assertIdentical($config->get('baz'), $expected_original_data['baz']); $this->assertIdentical($config->get('404'), $expected_original_data['404']); @@ -115,11 +117,11 @@ function testConfOverride() { 'foo' => 'barbar', '404' => 'herpderp', ); - $staging->write('config_test.system', $expected_new_data); + $staging->write($name, $expected_new_data); // Import changed data from staging to active. config_import(); - $data = $active->read('config_test.system'); + $data = $active->read($name); // Verify that the new configuration data exists. Have to read storage // directly otherwise overrides will apply. diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php index 439f191..23fe0dc 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -41,7 +42,7 @@ function testSnapshot() { $active = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); $snapshot = $this->container->get('config.storage.snapshot'); - $config_name = 'config_test.system'; + $config_name = new ConfigName('config_test.system'); $config_key = 'foo'; $new_data = 'foobar'; diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php index a2b3448..2d4e53c 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests\Storage; +use Drupal\Core\Config\ConfigName; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -30,7 +31,7 @@ * @todo Coverage: Trigger Yaml's ParseException and DumpException. */ function testCRUD() { - $name = 'config_test.storage'; + $name = new ConfigName('config_test.storage'); // Checking whether a non-existing name exists returns FALSE. $this->assertIdentical($this->storage->exists($name), FALSE); @@ -67,16 +68,16 @@ function testCRUD() { // Listing all names returns all. $names = $this->storage->listAll(); - $this->assertTrue(in_array('system.performance', $names)); + $this->assertTrue(in_array(new ConfigName('system.performance'), $names)); $this->assertTrue(in_array($name, $names)); // Listing all names with prefix returns names with that prefix only. $names = $this->storage->listAll('config_test.'); - $this->assertFalse(in_array('system.performance', $names)); + $this->assertFalse(in_array(new ConfigName('system.performance'), $names)); $this->assertTrue(in_array($name, $names)); // Rename the configuration storage object. - $new_name = 'config_test.storage_rename'; + $new_name = new ConfigName('config_test.storage_rename'); $this->storage->rename($name, $new_name); $raw_data = $this->read($new_name); $this->assertIdentical($raw_data, $data); @@ -103,7 +104,7 @@ function testCRUD() { 'config_test.test.pow', ); foreach ($files as $name) { - $this->storage->write($name, $data); + $this->storage->write(new ConfigName($name), $data); } $result = $this->storage->deleteAll('config_test.'); @@ -111,6 +112,7 @@ function testCRUD() { $this->assertIdentical($result, TRUE); $this->assertIdentical($names, array()); + $name = new ConfigName('config_test.test.pow'); // Writing to a non-existing storage bin throws an exception. try { $this->invalidStorage->write($name, array('foo' => 'bar')); @@ -143,7 +145,7 @@ function testCRUD() { // Test renaming an object that does not exist throws an exception. try { - $this->storage->rename('config_test.storage_does_not_exist', 'config_test.storage_does_not_exist_rename'); + $this->storage->rename(new ConfigName('config_test.storage_does_not_exist'), new ConfigName('config_test.storage_does_not_exist_rename')); } catch (\Exception $e) { $class = get_class($e); @@ -152,7 +154,7 @@ function testCRUD() { // Test renaming to an object that already exists throws an exception. try { - $this->storage->rename('system.cron', 'system.performance'); + $this->storage->rename(new ConfigName('system.cron'), new ConfigName('system.performance')); } catch (\Exception $e) { $class = get_class($e); diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php b/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php index 516bb9d..2209cfa 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests\Storage; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\DatabaseStorage; /** @@ -34,6 +35,13 @@ function setUp() { 'not null' => TRUE, 'default' => '', ), + 'owner' => array( + 'description' => 'The owner for the config object.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), 'data' => array( 'description' => 'The raw data for this configuration entry.', 'type' => 'blob', @@ -50,7 +58,7 @@ function setUp() { $this->invalidStorage = new DatabaseStorage($this->container->get('database'), 'invalid'); // ::listAll() verifications require other configuration data to exist. - $this->storage->write('system.performance', array()); + $this->storage->write(new ConfigName('system.performance'), array()); } protected function read($name) { diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php b/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php index d4d492a..278283a 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php @@ -7,6 +7,7 @@ namespace Drupal\config\Tests\Storage; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\FileStorage; use Symfony\Component\Yaml\Yaml; @@ -28,7 +29,8 @@ function setUp() { $this->invalidStorage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY] . '/nonexisting'); // FileStorage::listAll() requires other configuration data to exist. - $this->storage->write('system.performance', config('system.performance')->get()); + $name = new ConfigName('system.performance'); + $this->storage->write($name, config($name)->get()); } protected function read($name) { @@ -37,6 +39,7 @@ protected function read($name) { } protected function insert($name, $data) { + $this->storage->ensureOwnerDirectory($name); file_put_contents($this->storage->getFilePath($name), $data); } diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php index 5a85399..7afc274 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php @@ -10,6 +10,7 @@ use Drupal\Core\Config\Context\ConfigContext; use Drupal\Core\Config\Context\ContextInterface; use Drupal\Core\Config\ConfigEvent; +use Drupal\Core\Config\ConfigName; use Drupal\Core\Config\StorageDispatcher; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManager; @@ -110,7 +111,7 @@ public function onKernelRequestSetDefaultConfigContextLocale(GetResponseEvent $e * It will be the same name with a prefix depending on language code: * locale.config.LANGCODE.NAME * - * @param string $name + * @param ConfigName $name * The name of the config object. * @param \Drupal\Core\Language\Language $language * The language object. @@ -118,8 +119,8 @@ public function onKernelRequestSetDefaultConfigContextLocale(GetResponseEvent $e * @return string * The localized config name. */ - public function getLocaleConfigName($name, Language $language) { - return 'locale.config.' . $language->langcode . '.' . $name; + public function getLocaleConfigName(ConfigName $name, Language $language) { + return new ConfigName('locale.config.' . $language->langcode . '.' . $name, $name->getOwner()); } /** diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 08a9fd9..c6106f6 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1214,6 +1214,13 @@ function system_schema() { 'not null' => TRUE, 'default' => '', ), + 'owner' => array( + 'description' => 'The owner for the config object.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), 'data' => array( 'description' => 'The raw data for this configuration object.', 'type' => 'blob', diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php b/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php index 232a847..de0f1ce 100644 --- a/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php +++ b/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php @@ -7,7 +7,7 @@ namespace Drupal\views\Tests; -use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\InstallStorage; /** * Provides tests view data and the base test schema with sample data records. @@ -51,9 +51,9 @@ public static function importTestViews($class, $modules = array()) { continue; } - $source_storage = new FileStorage($config_dir); + $source_storage = new InstallStorage($config_dir); foreach ($source_storage->listAll('views.view.') as $config_name) { - $id = str_replace('views.view.', '', $config_name); + $id = str_replace('views.view.', '', (string) $config_name); if (in_array($id, $views)) { $config_changes['create'][] = $config_name; } diff --git a/core/modules/views/lib/Drupal/views/ViewsDataCache.php b/core/modules/views/lib/Drupal/views/ViewsDataCache.php index 15e338c..3aab318 100644 --- a/core/modules/views/lib/Drupal/views/ViewsDataCache.php +++ b/core/modules/views/lib/Drupal/views/ViewsDataCache.php @@ -7,8 +7,9 @@ namespace Drupal\views; -use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\ConfigFactory; +use Drupal\Core\Config\ConfigName; +use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\DestructableInterface; /** @@ -77,7 +78,7 @@ public function __construct(CacheBackendInterface $cache_backend, ConfigFactory $this->cacheBackend = $cache_backend; $this->langcode = language(LANGUAGE_TYPE_INTERFACE)->langcode; - $this->skipCache = $this->config->get('views.settings')->get('skip_cache'); + $this->skipCache = $this->config->get(new ConfigName('views.settings'))->get('skip_cache'); } /**