Issue #1702080 by sun, chx: Added Introduce canonical FileStorage + (regular) cache.
parent
4f37cf0255
commit
4b5fad5475
|
@ -2413,47 +2413,62 @@ function drupal_get_bootstrap_phase() {
|
|||
*
|
||||
* @see Drupal\Core\DrupalKernel
|
||||
*
|
||||
* @param $reset
|
||||
* A new container instance to reset the Drupal container to.
|
||||
* @param Symfony\Component\DependencyInjection\Container $new_container
|
||||
* A new container instance to replace the current.
|
||||
* @param bool $rebuild
|
||||
* (optional) Internal use only. Whether to enforce a rebuild of the container.
|
||||
* Used by the testing framework to inject a fresh container for unit tests.
|
||||
*
|
||||
* @return Symfony\Component\DependencyInjection\Container
|
||||
* The instance of the Container used to set up and maintain object
|
||||
* instances.
|
||||
*/
|
||||
function drupal_container(Container $reset = NULL) {
|
||||
function drupal_container(Container $new_container = NULL, $rebuild = FALSE) {
|
||||
// We do not use drupal_static() here because we do not have a mechanism by
|
||||
// which to reinitialize the stored objects, so a drupal_static_reset() call
|
||||
// would leave Drupal in a nonfunctional state.
|
||||
static $container = NULL;
|
||||
if (isset($reset)) {
|
||||
$container = $reset;
|
||||
if ($rebuild) {
|
||||
$container = NULL;
|
||||
}
|
||||
elseif (!isset($container)) {
|
||||
if (isset($new_container)) {
|
||||
$container = $new_container;
|
||||
}
|
||||
if (!isset($container)) {
|
||||
// Return a ContainerBuilder instance with the bare essentials needed for any
|
||||
// full bootstrap regardless of whether there will be a DrupalKernel involved.
|
||||
// This will get merged with the full Kernel-built Container on normal page
|
||||
// requests.
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
// Register configuration storage class and options.
|
||||
// @todo The active store and its options need to be configurable.
|
||||
// Use either global $conf (recursion warning) or global $config, or a
|
||||
// bootstrap configuration *file* to allow to set/override this very
|
||||
// lowest of low level configuration.
|
||||
$container->setParameter('config.storage.options', array(
|
||||
'connection' => 'default',
|
||||
'target' => 'default',
|
||||
));
|
||||
$container->register('config.storage', 'Drupal\Core\Config\DatabaseStorage')
|
||||
->addArgument('%config.storage.options%');
|
||||
// Register active configuration storage.
|
||||
$container
|
||||
->register('config.cachedstorage.storage', 'Drupal\Core\Config\FileStorage')
|
||||
->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY));
|
||||
// @todo Replace this with a cache.factory service plus 'config' argument.
|
||||
$container
|
||||
->register('cache.config')
|
||||
->setFactoryClass('Drupal\Core\Cache\CacheFactory')
|
||||
->setFactoryMethod('get')
|
||||
->addArgument('config');
|
||||
|
||||
$container
|
||||
->register('config.storage', 'Drupal\Core\Config\CachedStorage')
|
||||
->addArgument(new Reference('config.cachedstorage.storage'))
|
||||
->addArgument(new Reference('cache.config'));
|
||||
|
||||
// Register configuration object factory.
|
||||
$container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber');
|
||||
$container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
|
||||
->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf')));
|
||||
// Register configuration object factory.
|
||||
$container->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
|
||||
->addArgument(new Reference('config.storage'))
|
||||
->addArgument(new Reference('dispatcher'));
|
||||
|
||||
// Register staging configuration storage.
|
||||
$container
|
||||
->register('config.storage.staging', 'Drupal\Core\Config\FileStorage')
|
||||
->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY));
|
||||
}
|
||||
return $container;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* Functions and interfaces for cache handling.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Cache\CacheFactory;
|
||||
|
||||
/**
|
||||
* Instantiates and statically caches the correct class for a cache bin.
|
||||
*
|
||||
|
@ -32,9 +34,7 @@ function cache($bin = 'cache') {
|
|||
// storage of a cache bin mid-request.
|
||||
static $cache_objects;
|
||||
if (!isset($cache_objects[$bin])) {
|
||||
$cache_backends = cache_get_backends();
|
||||
$class = isset($cache_backends[$bin]) ? $cache_backends[$bin] : $cache_backends['cache'];
|
||||
$cache_objects[$bin] = new $class($bin);
|
||||
$cache_objects[$bin] = CacheFactory::get($bin);
|
||||
}
|
||||
return $cache_objects[$bin];
|
||||
}
|
||||
|
@ -53,17 +53,7 @@ function cache($bin = 'cache') {
|
|||
* The list of tags to invalidate cache items for.
|
||||
*/
|
||||
function cache_invalidate(array $tags) {
|
||||
foreach (cache_get_backends() as $bin => $class) {
|
||||
foreach (CacheFactory::getBackends() as $bin => $class) {
|
||||
cache($bin)->invalidateTags($tags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of cache backends for this site.
|
||||
*
|
||||
* @return
|
||||
* An associative array with cache bins as keys, and backend classes as value.
|
||||
*/
|
||||
function cache_get_backends() {
|
||||
return variable_get('cache_classes', array('cache' => 'Drupal\Core\Cache\DatabaseBackend'));
|
||||
}
|
||||
|
|
|
@ -17,14 +17,11 @@ use Drupal\Core\Config\StorageInterface;
|
|||
* The extension type; e.g., 'module' or 'theme'.
|
||||
* @param string $name
|
||||
* The name of the module or theme to install default configuration for.
|
||||
*
|
||||
* @todo Make this acknowledge other storage engines rather than having
|
||||
* SQL be hardcoded.
|
||||
*/
|
||||
function config_install_default_config($type, $name) {
|
||||
$config_dir = drupal_get_path($type, $name) . '/config';
|
||||
if (is_dir($config_dir)) {
|
||||
$source_storage = new FileStorage(array('directory' => $config_dir));
|
||||
$source_storage = new FileStorage($config_dir);
|
||||
$target_storage = drupal_container()->get('config.storage');
|
||||
$null_storage = new NullStorage();
|
||||
|
||||
|
@ -43,7 +40,9 @@ function config_install_default_config($type, $name) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @todo Modules need a way to access the active store, whatever it is.
|
||||
* Gets configuration object names starting with a given prefix.
|
||||
*
|
||||
* @see Drupal\Core\Config\StorageInterface::listAll()
|
||||
*/
|
||||
function config_get_storage_names_with_prefix($prefix = '') {
|
||||
return drupal_container()->get('config.storage')->listAll($prefix);
|
||||
|
@ -137,7 +136,7 @@ function config_sync_changes(array $config_changes, StorageInterface $source_sto
|
|||
*/
|
||||
function config_import() {
|
||||
// Retrieve a list of differences between staging and the active store.
|
||||
$source_storage = new FileStorage(array('directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY)));
|
||||
$source_storage = drupal_container()->get('config.storage.staging');
|
||||
$target_storage = drupal_container()->get('config.storage');
|
||||
|
||||
$config_changes = config_sync_get_changes($source_storage, $target_storage);
|
||||
|
@ -219,7 +218,7 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou
|
|||
function config_export() {
|
||||
// Retrieve a list of differences between the active store and staging.
|
||||
$source_storage = drupal_container()->get('config.storage');
|
||||
$target_storage = new FileStorage(array('directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY)));
|
||||
$target_storage = drupal_container()->get('config.storage.staging');
|
||||
|
||||
$config_changes = config_sync_get_changes($source_storage, $target_storage);
|
||||
if (empty($config_changes)) {
|
||||
|
|
|
@ -5,6 +5,8 @@ use Drupal\Core\Database\Database;
|
|||
use Drupal\Core\Database\Install\TaskException;
|
||||
use Drupal\Core\Language\Language;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
@ -272,6 +274,46 @@ function install_begin_request(&$install_state) {
|
|||
include_once DRUPAL_ROOT . '/core/includes/module.inc';
|
||||
include_once DRUPAL_ROOT . '/core/includes/session.inc';
|
||||
|
||||
// Determine whether the configuration system is ready to operate.
|
||||
$install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_verify_config_directory(CONFIG_STAGING_DIRECTORY);
|
||||
|
||||
// If it is not, replace the configuration storage with the InstallStorage
|
||||
// implementation, for the following reasons:
|
||||
// - The first call into drupal_container() will try to set up the regular
|
||||
// runtime configuration storage, using the CachedStorage by default. It
|
||||
// calls config_get_config_directory() to retrieve the config directory to
|
||||
// use, but that throws an exception, since $config_directories is not
|
||||
// defined since there is no settings.php yet. If there is a prepared
|
||||
// settings.php already, then the returned directory still cannot be used,
|
||||
// because it does not necessarily exist. The installer ensures that it
|
||||
// exists and is writeable in a later step.
|
||||
// - The installer outputs maintenance theme pages and performs many other
|
||||
// operations, which try to load configuration. Since there is no active
|
||||
// configuration yet, and because the configuration system does not have a
|
||||
// notion of default values at runtime, data is missing in many places. The
|
||||
// lack of data does not trigger errors, but results in a broken user
|
||||
// interface (e.g., missing page title, etc).
|
||||
// - The actual configuration data to read during installation is essentially
|
||||
// the default configuration provided by the installation profile and
|
||||
// modules (most notably System module). The InstallStorage therefore reads
|
||||
// from the default configuration directories of extensions.
|
||||
// This override is reverted as soon as the config directory has been set up
|
||||
// successfully.
|
||||
// @see drupal_install_config_directories()
|
||||
if (!$install_state['config_verified']) {
|
||||
// @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder.
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher');
|
||||
|
||||
$container->register('config.storage', 'Drupal\Core\Config\InstallStorage');
|
||||
$container->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
|
||||
->addArgument(new Reference('config.storage'))
|
||||
->addArgument(new Reference('dispatcher'));
|
||||
|
||||
drupal_container($container);
|
||||
}
|
||||
|
||||
// Set up $language, so t() caller functions will still work.
|
||||
drupal_language_initialize();
|
||||
|
||||
|
@ -316,7 +358,6 @@ function install_begin_request(&$install_state) {
|
|||
|
||||
// Check existing settings.php.
|
||||
$install_state['database_verified'] = install_verify_database_settings();
|
||||
$install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_verify_config_directory(CONFIG_STAGING_DIRECTORY);
|
||||
$install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified'];
|
||||
|
||||
if ($install_state['database_verified']) {
|
||||
|
@ -1054,6 +1095,11 @@ function install_settings_form_submit($form, &$form_state) {
|
|||
// Add the config directories to settings.php.
|
||||
drupal_install_config_directories();
|
||||
|
||||
// We have valid configuration directories in settings.php.
|
||||
// Reset the service container, so the config.storage service will use the
|
||||
// actual active storage for installing configuration.
|
||||
drupal_container(NULL, TRUE);
|
||||
|
||||
// Indicate that the settings file has been verified, and check the database
|
||||
// for the last completed task, now that we have a valid connection. This
|
||||
// last step is important since we want to trigger an error if the new
|
||||
|
|
|
@ -275,7 +275,7 @@ function drupal_install_config_directories() {
|
|||
drupal_rewrite_settings($settings);
|
||||
}
|
||||
|
||||
// Ensure that the config directory exists or can be created, and is writable.
|
||||
// Ensure the config directories exist or can be created, and are writable.
|
||||
foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) {
|
||||
// This should never fail, since if the config directory was specified in
|
||||
// settings.php it will have already been created and verified earlier, and
|
||||
|
@ -296,7 +296,7 @@ function drupal_install_config_directories() {
|
|||
* Checks whether a config directory name is defined, and if so, whether it
|
||||
* exists and is writable.
|
||||
*
|
||||
* This partically duplicates install_ensure_config_directory(), but is required
|
||||
* This partially duplicates install_ensure_config_directory(), but is required
|
||||
* since the installer would create the config directory too early in the
|
||||
* installation process otherwise (e.g., when only visiting install.php when
|
||||
* there is a settings.php already, but not actually executing the installation).
|
||||
|
@ -313,9 +313,16 @@ function install_verify_config_directory($type) {
|
|||
if (!isset($config_directories[$type])) {
|
||||
return FALSE;
|
||||
}
|
||||
$config_directory = config_get_config_directory($type);
|
||||
if (is_dir($config_directory) && is_writable($config_directory)) {
|
||||
return TRUE;
|
||||
// config_get_config_directory() throws an exception when the passed $type
|
||||
// does not exist in $config_directories. This can happen if there is a
|
||||
// prepared settings.php that defines $config_directories already.
|
||||
try {
|
||||
$config_directory = config_get_config_directory($type);
|
||||
if (is_dir($config_directory) && is_writable($config_directory)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
use Drupal\Component\Graph\Graph;
|
||||
use Drupal\Core\Config\DatabaseStorage;
|
||||
|
||||
/**
|
||||
* Loads all the modules that have been enabled in the system table.
|
||||
|
@ -617,7 +616,7 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE)
|
|||
$module_list = array_keys($module_list);
|
||||
}
|
||||
|
||||
$storage = new DatabaseStorage();
|
||||
$storage = drupal_container()->get('config.storage');
|
||||
foreach ($module_list as $module) {
|
||||
// Uninstall the module.
|
||||
module_load_install($module);
|
||||
|
|
|
@ -1056,7 +1056,7 @@ function update_variables_to_config($config_name, array $variable_map) {
|
|||
$module = strtok($config_name, '.');
|
||||
|
||||
// Load and set default configuration values.
|
||||
$file = new FileStorage(array('directory' => drupal_get_path('module', $module) . '/config'));
|
||||
$file = new FileStorage(drupal_get_path('module', $module) . '/config');
|
||||
if (!$file->exists($config_name)) {
|
||||
throw new ConfigException("Default configuration file $config_name for $module extension not found but is required to exist.");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\Core\Cache\CacheFactory.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache;
|
||||
|
||||
/**
|
||||
* Defines the cache backend factory.
|
||||
*/
|
||||
class CacheFactory {
|
||||
|
||||
/**
|
||||
* Instantiates a cache backend class for a given cache bin.
|
||||
*
|
||||
* By default, this returns an instance of the
|
||||
* Drupal\Core\Cache\DatabaseBackend class.
|
||||
*
|
||||
* Classes implementing Drupal\Core\Cache\CacheBackendInterface can register
|
||||
* themselves both as a default implementation and for specific bins.
|
||||
*
|
||||
* @param string $bin
|
||||
* The cache bin for which a cache backend object should be returned.
|
||||
*
|
||||
* @return Drupal\Core\Cache\CacheBackendInterface
|
||||
* The cache backend object associated with the specified bin.
|
||||
*/
|
||||
public static function get($bin) {
|
||||
// Check whether there is a custom class defined for the requested bin or
|
||||
// use the default 'cache' definition otherwise.
|
||||
$cache_backends = self::getBackends();
|
||||
$class = isset($cache_backends[$bin]) ? $cache_backends[$bin] : $cache_backends['cache'];
|
||||
return new $class($bin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of cache backends for this site.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with cache bins as keys, and backend class names as
|
||||
* value.
|
||||
*/
|
||||
public static function getBackends() {
|
||||
// @todo Improve how cache backend classes are defined. Cannot be
|
||||
// configuration, since e.g. the CachedStorage config storage controller
|
||||
// requires the definition in its constructor already.
|
||||
global $conf;
|
||||
$cache_backends = isset($conf['cache_classes']) ? $conf['cache_classes'] : array();
|
||||
// Ensure there is a default 'cache' bin definition.
|
||||
$cache_backends += array('cache' => 'Drupal\Core\Cache\DatabaseBackend');
|
||||
return $cache_backends;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\Core\Config\CachedStorage.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
|
||||
/**
|
||||
* Defines the cached storage controller.
|
||||
*
|
||||
* The class gets another storage and a cache backend injected. It reads from
|
||||
* the cache and delegates the read to the storage on a cache miss. It also
|
||||
* handles cache invalidation.
|
||||
*/
|
||||
class CachedStorage implements StorageInterface {
|
||||
|
||||
/**
|
||||
* The configuration storage to be cached.
|
||||
*
|
||||
* @var Drupal\Core\Config\StorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The instantiated Cache backend.
|
||||
*
|
||||
* @var Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Constructs a new CachedStorage controller.
|
||||
*
|
||||
* @param Drupal\Core\Config\StorageInterface $storage
|
||||
* A configuration storage controller to be cached.
|
||||
* @param Drupal\Core\Cache\CacheBackendInterface $cache
|
||||
* A cache backend instance to use for caching.
|
||||
*/
|
||||
public function __construct(StorageInterface $storage, CacheBackendInterface $cache) {
|
||||
$this->storage = $storage;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::exists().
|
||||
*/
|
||||
public function exists($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.
|
||||
return $this->storage->exists($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::read().
|
||||
*/
|
||||
public function read($name) {
|
||||
if ($cache = $this->cache->get($name)) {
|
||||
// The cache backend supports primitive data types, but only an array
|
||||
// represents valid config object data.
|
||||
if (is_array($cache->data)) {
|
||||
return $cache->data;
|
||||
}
|
||||
}
|
||||
// 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, array('config' => array($name)));
|
||||
}
|
||||
// If the cache contained bogus data and there is no data in the storage,
|
||||
// wipe the cache entry.
|
||||
elseif ($cache) {
|
||||
$this->cache->delete($name);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::write().
|
||||
*/
|
||||
public function write($name, array $data) {
|
||||
if ($this->storage->write($name, $data)) {
|
||||
// While not all written data is read back, setting the cache instead of
|
||||
// just deleting it avoids cache rebuild stampedes.
|
||||
$this->cache->set($name, $data, CacheBackendInterface::CACHE_PERMANENT, array('config' => array($name)));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::delete().
|
||||
*/
|
||||
public function delete($name) {
|
||||
// If the cache was the first to be deleted, another process might start
|
||||
// rebuilding the cache before the storage is gone.
|
||||
if ($this->storage->delete($name)) {
|
||||
$this->cache->delete($name);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::rename().
|
||||
*/
|
||||
public function rename($name, $new_name) {
|
||||
// If the cache was the first to be deleted, another process might start
|
||||
// rebuilding the cache before the storage is renamed.
|
||||
if ($this->storage->rename($name, $new_name)) {
|
||||
$this->cache->delete($name);
|
||||
$this->cache->delete($new_name);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::encode().
|
||||
*/
|
||||
public function encode($data) {
|
||||
return $this->storage->encode($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::decode().
|
||||
*/
|
||||
public function decode($raw) {
|
||||
return $this->storage->decode($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::listAll().
|
||||
*
|
||||
* Not supported by CacheBackendInterface.
|
||||
*/
|
||||
public function listAll($prefix = '') {
|
||||
return $this->storage->listAll($prefix);
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
|
@ -16,31 +17,49 @@ use Exception;
|
|||
class DatabaseStorage implements StorageInterface {
|
||||
|
||||
/**
|
||||
* Database connection options for this storage controller.
|
||||
* The database connection.
|
||||
*
|
||||
* - connection: The connection key to use.
|
||||
* - target: The target on the connection to use.
|
||||
* @var Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The database table name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* Additional database connection options to use in queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
protected $options = array();
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::__construct().
|
||||
* Constructs a new DatabaseStorage controller.
|
||||
*
|
||||
* @param Drupal\Core\Database\Connection $connection
|
||||
* A Database connection to use for reading and writing configuration data.
|
||||
* @param string $table
|
||||
* A database table name to store configuration data in.
|
||||
* @param array $options
|
||||
* (optional) Any additional database connection options to use in queries.
|
||||
*/
|
||||
public function __construct(array $options = array()) {
|
||||
$options += array(
|
||||
'connection' => 'default',
|
||||
'target' => 'default',
|
||||
);
|
||||
public function __construct(Connection $connection, $table, array $options = array()) {
|
||||
$this->connection = $connection;
|
||||
$this->table = $table;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database connection to use.
|
||||
* Implements Drupal\Core\Config\StorageInterface::exists().
|
||||
*/
|
||||
protected function getConnection() {
|
||||
return Database::getConnection($this->options['target'], $this->options['connection']);
|
||||
public function exists($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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,10 +75,8 @@ class DatabaseStorage implements StorageInterface {
|
|||
// read without actually having the database available. In this case,
|
||||
// catch the exception and just return an empty array so the caller can
|
||||
// handle it if need be.
|
||||
// @todo Remove this and use appropriate config.storage service definition
|
||||
// in the installer instead.
|
||||
try {
|
||||
$raw = $this->getConnection()->query('SELECT data FROM {config} WHERE name = :name', array(':name' => $name), $this->options)->fetchField();
|
||||
$raw = $this->connection->query('SELECT data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name = :name', array(':name' => $name), $this->options)->fetchField();
|
||||
if ($raw !== FALSE) {
|
||||
$data = $this->decode($raw);
|
||||
}
|
||||
|
@ -79,7 +96,7 @@ class DatabaseStorage implements StorageInterface {
|
|||
public function write($name, array $data) {
|
||||
$data = $this->encode($data);
|
||||
$options = array('return' => Database::RETURN_AFFECTED) + $this->options;
|
||||
return (bool) $this->getConnection()->merge('config', $options)
|
||||
return (bool) $this->connection->merge($this->table, $options)
|
||||
->key(array('name' => $name))
|
||||
->fields(array('data' => $data))
|
||||
->execute();
|
||||
|
@ -94,7 +111,7 @@ class DatabaseStorage implements StorageInterface {
|
|||
*/
|
||||
public function delete($name) {
|
||||
$options = array('return' => Database::RETURN_AFFECTED) + $this->options;
|
||||
return (bool) $this->getConnection()->delete('config', $options)
|
||||
return (bool) $this->connection->delete($this->table, $options)
|
||||
->condition('name', $name)
|
||||
->execute();
|
||||
}
|
||||
|
@ -107,7 +124,7 @@ class DatabaseStorage implements StorageInterface {
|
|||
*/
|
||||
public function rename($name, $new_name) {
|
||||
$options = array('return' => Database::RETURN_AFFECTED) + $this->options;
|
||||
return (bool) $this->getConnection()->update('config', $options)
|
||||
return (bool) $this->connection->update($this->table, $options)
|
||||
->fields(array('name' => $new_name))
|
||||
->condition('name', $name)
|
||||
->execute();
|
||||
|
@ -139,7 +156,7 @@ class DatabaseStorage implements StorageInterface {
|
|||
* Only thrown in case $this->options['throw_exception'] is TRUE.
|
||||
*/
|
||||
public function listAll($prefix = '') {
|
||||
return $this->getConnection()->query('SELECT name FROM {config} WHERE name LIKE :name', array(
|
||||
return $this->connection->query('SELECT name FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name LIKE :name', array(
|
||||
':name' => db_like($prefix) . '%',
|
||||
), $this->options)->fetchCol();
|
||||
}
|
||||
|
|
|
@ -16,13 +16,11 @@ use Symfony\Component\Yaml\Parser;
|
|||
class FileStorage implements StorageInterface {
|
||||
|
||||
/**
|
||||
* Configuration options for this storage controller.
|
||||
* The filesystem path for configuration objects.
|
||||
*
|
||||
* - directory: The filesystem path for configuration objects.
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
protected $options;
|
||||
protected $directory = '';
|
||||
|
||||
/**
|
||||
* A shared YAML dumper instance.
|
||||
|
@ -39,13 +37,13 @@ class FileStorage implements StorageInterface {
|
|||
protected $parser;
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::__construct().
|
||||
* Constructs a new FileStorage controller.
|
||||
*
|
||||
* @param string $directory
|
||||
* A directory path to use for reading and writing of configuration files.
|
||||
*/
|
||||
public function __construct(array $options = array()) {
|
||||
if (!isset($options['directory'])) {
|
||||
$options['directory'] = config_get_config_directory();
|
||||
}
|
||||
$this->options = $options;
|
||||
public function __construct($directory) {
|
||||
$this->directory = $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +53,7 @@ class FileStorage implements StorageInterface {
|
|||
* The path to the configuration file.
|
||||
*/
|
||||
public function getFilePath($name) {
|
||||
return $this->options['directory'] . '/' . $name . '.' . self::getFileExtension();
|
||||
return $this->directory . '/' . $name . '.' . self::getFileExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,8 +112,8 @@ class FileStorage implements StorageInterface {
|
|||
*/
|
||||
public function delete($name) {
|
||||
if (!$this->exists($name)) {
|
||||
if (!file_exists($this->options['directory'])) {
|
||||
throw new StorageException($this->options['directory'] . '/ not found.');
|
||||
if (!file_exists($this->directory)) {
|
||||
throw new StorageException($this->directory . '/ not found.');
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -188,11 +186,11 @@ class FileStorage implements StorageInterface {
|
|||
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->options['directory'])) {
|
||||
throw new StorageException($this->options['directory'] . '/ not found.');
|
||||
if (!file_exists($this->directory)) {
|
||||
throw new StorageException($this->directory . '/ not found.');
|
||||
}
|
||||
$extension = '.' . self::getFileExtension();
|
||||
$files = glob($this->options['directory'] . '/' . $prefix . '*' . $extension);
|
||||
$files = glob($this->directory . '/' . $prefix . '*' . $extension);
|
||||
$clean_name = function ($value) use ($extension) {
|
||||
return basename($value, $extension);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\Core\Config\InstallStorage.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
/**
|
||||
* Storage controller used by the Drupal installer.
|
||||
*
|
||||
* @see install_begin_request()
|
||||
*/
|
||||
class InstallStorage extends FileStorage {
|
||||
|
||||
/**
|
||||
* Overrides Drupal\Core\Config\FileStorage::__construct().
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @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($name) {
|
||||
// Extract the owner.
|
||||
$owner = strtok($name, '.');
|
||||
// Determine the path to the owner.
|
||||
$path = FALSE;
|
||||
foreach (array('profile', 'module', 'theme') as $type) {
|
||||
if ($path = drupal_get_path($type, $owner)) {
|
||||
$file = $path . '/config/' . $name . '.' . self::getFileExtension();
|
||||
if (file_exists($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If any code in the early installer requests a configuration object that
|
||||
// does not exist anywhere as default config, then that must be mistake.
|
||||
throw new StorageException(format_string('Missing configuration file: @name', array(
|
||||
'@name' => $name,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\Core\Config\FileStorage::write().
|
||||
*
|
||||
* @throws Drupal\Core\Config\StorageException
|
||||
*/
|
||||
public function write($name, array $data) {
|
||||
throw new StorageException('Write operation is not allowed during install.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\Core\Config\FileStorage::delete().
|
||||
*
|
||||
* @throws Drupal\Core\Config\StorageException
|
||||
*/
|
||||
public function delete($name) {
|
||||
throw new StorageException('Delete operation is not allowed during install.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\Core\Config\FileStorage::rename().
|
||||
*
|
||||
* @throws Drupal\Core\Config\StorageException
|
||||
*/
|
||||
public function rename($name, $new_name) {
|
||||
throw new StorageException('Rename operation is not allowed during install.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::listAll().
|
||||
*
|
||||
* @throws Drupal\Core\Config\StorageException
|
||||
*/
|
||||
public function listAll($prefix = '') {
|
||||
throw new StorageException('List operation is not allowed during install.');
|
||||
}
|
||||
}
|
|
@ -22,10 +22,12 @@ namespace Drupal\Core\Config;
|
|||
* This also can be used for testing purposes.
|
||||
*/
|
||||
class NullStorage implements StorageInterface {
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::__construct().
|
||||
* Implements Drupal\Core\Config\StorageInterface::exists().
|
||||
*/
|
||||
public function __construct(array $options = array()) {
|
||||
public function exists($name) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,13 +16,15 @@ namespace Drupal\Core\Config;
|
|||
interface StorageInterface {
|
||||
|
||||
/**
|
||||
* Constructs the storage controller.
|
||||
* Returns whether a configuration object exists.
|
||||
*
|
||||
* @param array $options
|
||||
* An associative array containing configuration options specific to the
|
||||
* storage controller.
|
||||
* @param string $name
|
||||
* The name of a configuration object to test.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the configuration object exists, FALSE otherwise.
|
||||
*/
|
||||
public function __construct(array $options = array());
|
||||
public function exists($name);
|
||||
|
||||
/**
|
||||
* Reads configuration data from the storage.
|
||||
|
|
|
@ -277,7 +277,8 @@ class ConfigStorageController implements StorageControllerInterface {
|
|||
// Configuration objects do not have a schema. Extract all key names from
|
||||
// class properties.
|
||||
$class_info = new \ReflectionClass($entity);
|
||||
foreach ($class_info->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
|
||||
$properties = $class_info->getProperties(\ReflectionProperty::IS_PUBLIC);
|
||||
foreach ($properties as $property) {
|
||||
$name = $property->getName();
|
||||
$config->set($name, $entity->$name);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\config\Tests;
|
||||
|
||||
use Drupal\Core\Config\DatabaseStorage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
|
@ -26,7 +25,7 @@ class ConfigCRUDTest extends WebTestBase {
|
|||
* Tests CRUD operations.
|
||||
*/
|
||||
function testCRUD() {
|
||||
$storage = new DatabaseStorage();
|
||||
$storage = $this->container->get('config.storage');
|
||||
$name = 'config_test.crud';
|
||||
|
||||
$config = config($name);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\config\Tests;
|
||||
|
||||
use Drupal\Core\Config\DatabaseStorage;
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
|
@ -23,15 +22,11 @@ class ConfigFileContentTest extends WebTestBase {
|
|||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting, writing, and reading of a configuration setting.
|
||||
*/
|
||||
function testReadWriteConfig() {
|
||||
$database_storage = new DatabaseStorage();
|
||||
$storage = $this->container->get('config.storage');
|
||||
|
||||
$name = 'foo.bar';
|
||||
$key = 'foo';
|
||||
|
@ -67,8 +62,8 @@ class ConfigFileContentTest extends WebTestBase {
|
|||
$this->assertEqual($config->get(), array(), t('New config object is empty.'));
|
||||
|
||||
// Verify nothing was saved.
|
||||
$db_data = $database_storage->read($name);
|
||||
$this->assertIdentical($db_data, FALSE);
|
||||
$data = $storage->read($name);
|
||||
$this->assertIdentical($data, FALSE);
|
||||
|
||||
// Add a top level value
|
||||
$config = config($name);
|
||||
|
@ -94,8 +89,8 @@ class ConfigFileContentTest extends WebTestBase {
|
|||
$config->save();
|
||||
|
||||
// Verify the database entry exists.
|
||||
$db_data = $database_storage->read($name);
|
||||
$this->assertTrue($db_data);
|
||||
$data = $storage->read($name);
|
||||
$this->assertTrue($data);
|
||||
|
||||
// Read top level value
|
||||
$config = config($name);
|
||||
|
@ -152,27 +147,27 @@ class ConfigFileContentTest extends WebTestBase {
|
|||
$config->set($key, $value)->save();
|
||||
|
||||
// Verify the database entry exists from a chained save.
|
||||
$db_data = $database_storage->read($chained_name);
|
||||
$this->assertEqual($db_data, $config->get());
|
||||
$data = $storage->read($chained_name);
|
||||
$this->assertEqual($data, $config->get());
|
||||
|
||||
// Get file listing for all files starting with 'foo'. Should return
|
||||
// two elements.
|
||||
$files = $database_storage->listAll('foo');
|
||||
$files = $storage->listAll('foo');
|
||||
$this->assertEqual(count($files), 2, 'Two files listed with the prefix \'foo\'.');
|
||||
|
||||
// Get file listing for all files starting with 'biff'. Should return
|
||||
// one element.
|
||||
$files = $database_storage->listAll('biff');
|
||||
$files = $storage->listAll('biff');
|
||||
$this->assertEqual(count($files), 1, 'One file listed with the prefix \'biff\'.');
|
||||
|
||||
// Get file listing for all files starting with 'foo.bar'. Should return
|
||||
// one element.
|
||||
$files = $database_storage->listAll('foo.bar');
|
||||
$files = $storage->listAll('foo.bar');
|
||||
$this->assertEqual(count($files), 1, 'One file listed with the prefix \'foo.bar\'.');
|
||||
|
||||
// Get file listing for all files starting with 'bar'. Should return
|
||||
// an empty array.
|
||||
$files = $database_storage->listAll('bar');
|
||||
$files = $storage->listAll('bar');
|
||||
$this->assertEqual($files, array(), 'No files listed with the prefix \'bar\'.');
|
||||
|
||||
// Delete the configuration.
|
||||
|
@ -180,8 +175,8 @@ class ConfigFileContentTest extends WebTestBase {
|
|||
$config->delete();
|
||||
|
||||
// Verify the database entry no longer exists.
|
||||
$db_data = $database_storage->read($name);
|
||||
$this->assertIdentical($db_data, FALSE);
|
||||
$data = $storage->read($name);
|
||||
$this->assertIdentical($data, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,7 +200,7 @@ class ConfigFileContentTest extends WebTestBase {
|
|||
);
|
||||
|
||||
// Encode and write, and reload and decode the configuration data.
|
||||
$filestorage = new FileStorage();
|
||||
$filestorage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]);
|
||||
$filestorage->write($name, $config_data);
|
||||
$config_parsed = $filestorage->read($name);
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
namespace Drupal\config\Tests;
|
||||
|
||||
use Drupal\Core\Config\DatabaseStorage;
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
|
@ -64,8 +62,8 @@ class ConfigImportTest extends WebTestBase {
|
|||
function testDeleted() {
|
||||
$name = 'config_test.system';
|
||||
$dynamic_name = 'config_test.dynamic.default';
|
||||
$active_storage = new DatabaseStorage();
|
||||
$staging_storage = new FileStorage(array('directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY)));
|
||||
$storage = $this->container->get('config.storage');
|
||||
$staging = $this->container->get('config.storage.staging');
|
||||
|
||||
// Verify the default configuration values exist.
|
||||
$config = config($name);
|
||||
|
@ -77,15 +75,15 @@ class ConfigImportTest extends WebTestBase {
|
|||
config_export();
|
||||
|
||||
// Delete the configuration objects from the staging directory.
|
||||
$staging_storage->delete($name);
|
||||
$staging_storage->delete($dynamic_name);
|
||||
$staging->delete($name);
|
||||
$staging->delete($dynamic_name);
|
||||
|
||||
// Import.
|
||||
config_import();
|
||||
|
||||
// Verify the values have disappeared.
|
||||
$this->assertIdentical($active_storage->read($name), FALSE);
|
||||
$this->assertIdentical($active_storage->read($dynamic_name), FALSE);
|
||||
$this->assertIdentical($storage->read($name), FALSE);
|
||||
$this->assertIdentical($storage->read($dynamic_name), FALSE);
|
||||
|
||||
$config = config($name);
|
||||
$this->assertIdentical($config->get('foo'), NULL);
|
||||
|
@ -99,6 +97,9 @@ class ConfigImportTest extends WebTestBase {
|
|||
$this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
|
||||
$this->assertTrue(isset($GLOBALS['hook_config_test']['predelete']));
|
||||
$this->assertTrue(isset($GLOBALS['hook_config_test']['delete']));
|
||||
|
||||
// Verify that there is nothing more to import.
|
||||
$this->assertFalse(config_sync_get_changes($staging, $storage));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,27 +108,34 @@ class ConfigImportTest extends WebTestBase {
|
|||
function testNew() {
|
||||
$name = 'config_test.new';
|
||||
$dynamic_name = 'config_test.dynamic.new';
|
||||
$staging_storage = new FileStorage(array('directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY)));
|
||||
$storage = $this->container->get('config.storage');
|
||||
$staging = $this->container->get('config.storage.staging');
|
||||
|
||||
// Export.
|
||||
config_export();
|
||||
|
||||
// Verify the configuration to create does not exist yet.
|
||||
$this->assertIdentical($staging_storage->exists($name), FALSE, $name . ' not found.');
|
||||
$this->assertIdentical($staging_storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.');
|
||||
$this->assertIdentical($storage->exists($name), FALSE, $name . ' not found.');
|
||||
$this->assertIdentical($storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.');
|
||||
|
||||
$this->assertIdentical($staging->exists($name), FALSE, $name . ' not found.');
|
||||
$this->assertIdentical($staging->exists($dynamic_name), FALSE, $dynamic_name . ' not found.');
|
||||
|
||||
// Create new configuration objects in the staging directory.
|
||||
$original_name_data = array(
|
||||
'add_me' => 'new value',
|
||||
);
|
||||
$staging_storage->write($name, $original_name_data);
|
||||
$staging->write($name, $original_name_data);
|
||||
$original_dynamic_data = array(
|
||||
'id' => 'new',
|
||||
'label' => 'New',
|
||||
'langcode' => 'und',
|
||||
'style' => '',
|
||||
'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651',
|
||||
);
|
||||
$staging_storage->write($dynamic_name, $original_dynamic_data);
|
||||
$this->assertIdentical($staging_storage->exists($name), TRUE, $name . ' found.');
|
||||
$this->assertIdentical($staging_storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
||||
$staging->write($dynamic_name, $original_dynamic_data);
|
||||
$this->assertIdentical($staging->exists($name), TRUE, $name . ' found.');
|
||||
$this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
||||
|
||||
// Import.
|
||||
config_import();
|
||||
|
@ -145,6 +153,9 @@ class ConfigImportTest extends WebTestBase {
|
|||
$this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
|
||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
|
||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
|
||||
|
||||
// Verify that there is nothing more to import.
|
||||
$this->assertFalse(config_sync_get_changes($staging, $storage));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,26 +164,28 @@ class ConfigImportTest extends WebTestBase {
|
|||
function testUpdated() {
|
||||
$name = 'config_test.system';
|
||||
$dynamic_name = 'config_test.dynamic.default';
|
||||
$staging_storage = new FileStorage(array('directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY)));
|
||||
$storage = $this->container->get('config.storage');
|
||||
$staging = $this->container->get('config.storage.staging');
|
||||
|
||||
// Export.
|
||||
config_export();
|
||||
|
||||
// Verify that the configuration objects to import exist.
|
||||
$this->assertIdentical($staging_storage->exists($name), TRUE, $name . ' found.');
|
||||
$this->assertIdentical($staging_storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
||||
$this->assertIdentical($storage->exists($name), TRUE, $name . ' found.');
|
||||
$this->assertIdentical($storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
||||
|
||||
$this->assertIdentical($staging->exists($name), TRUE, $name . ' found.');
|
||||
$this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
||||
|
||||
// Replace the file content of the existing configuration objects in the
|
||||
// staging directory.
|
||||
$original_name_data = array(
|
||||
'foo' => 'beer',
|
||||
);
|
||||
$staging_storage->write($name, $original_name_data);
|
||||
$original_dynamic_data = array(
|
||||
'id' => 'default',
|
||||
'label' => 'Updated',
|
||||
);
|
||||
$staging_storage->write($dynamic_name, $original_dynamic_data);
|
||||
$staging->write($name, $original_name_data);
|
||||
$original_dynamic_data = $staging->read($dynamic_name);
|
||||
$original_dynamic_data['label'] = 'Updated';
|
||||
$staging->write($dynamic_name, $original_dynamic_data);
|
||||
|
||||
// Verify the active store still returns the default values.
|
||||
$config = config($name);
|
||||
|
@ -190,8 +203,8 @@ class ConfigImportTest extends WebTestBase {
|
|||
$this->assertIdentical($config->get('label'), 'Updated');
|
||||
|
||||
// Verify that the original file content is still the same.
|
||||
$this->assertIdentical($staging_storage->read($name), $original_name_data);
|
||||
$this->assertIdentical($staging_storage->read($dynamic_name), $original_dynamic_data);
|
||||
$this->assertIdentical($staging->read($name), $original_name_data);
|
||||
$this->assertIdentical($staging->read($dynamic_name), $original_dynamic_data);
|
||||
|
||||
// Verify that appropriate module API hooks have been invoked.
|
||||
$this->assertTrue(isset($GLOBALS['hook_config_test']['load']));
|
||||
|
@ -200,6 +213,9 @@ class ConfigImportTest extends WebTestBase {
|
|||
$this->assertTrue(isset($GLOBALS['hook_config_test']['update']));
|
||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
|
||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
|
||||
|
||||
// Verify that there is nothing more to import.
|
||||
$this->assertFalse(config_sync_get_changes($staging, $storage));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ abstract class ConfigStorageTestBase extends WebTestBase {
|
|||
function testCRUD() {
|
||||
$name = 'config_test.storage';
|
||||
|
||||
// Checking whether a non-existing name exists returns FALSE.
|
||||
$this->assertIdentical($this->storage->exists($name), FALSE);
|
||||
|
||||
// Reading a non-existing name returns FALSE.
|
||||
$data = $this->storage->read($name);
|
||||
$this->assertIdentical($data, FALSE);
|
||||
|
@ -51,9 +54,13 @@ abstract class ConfigStorageTestBase extends WebTestBase {
|
|||
$data = array('foo' => 'bar');
|
||||
$result = $this->storage->write($name, $data);
|
||||
$this->assertIdentical($result, TRUE);
|
||||
|
||||
$raw_data = $this->read($name);
|
||||
$this->assertIdentical($raw_data, $data);
|
||||
|
||||
// Checking whether an existing name exists returns TRUE.
|
||||
$this->assertIdentical($this->storage->exists($name), TRUE);
|
||||
|
||||
// Writing the identical data again still returns TRUE.
|
||||
$result = $this->storage->write($name, $data);
|
||||
$this->assertIdentical($result, TRUE);
|
||||
|
|
|
@ -23,8 +23,34 @@ class DatabaseStorageTest extends ConfigStorageTestBase {
|
|||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->storage = new DatabaseStorage();
|
||||
$this->invalidStorage = new DatabaseStorage(array('connection' => 'invalid'));
|
||||
|
||||
$schema['config'] = array(
|
||||
'description' => 'Default active store for the configuration system.',
|
||||
'fields' => array(
|
||||
'name' => array(
|
||||
'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'data' => array(
|
||||
'description' => 'The raw data for this configuration entry.',
|
||||
'type' => 'blob',
|
||||
'not null' => TRUE,
|
||||
'size' => 'big',
|
||||
'translatable' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('name'),
|
||||
);
|
||||
db_create_table('config', $schema['config']);
|
||||
|
||||
$this->storage = new DatabaseStorage($this->container->get('database'), 'config');
|
||||
$this->invalidStorage = new DatabaseStorage($this->container->get('database'), 'invalid');
|
||||
|
||||
// ::listAll() verifications require other configuration data to exist.
|
||||
$this->storage->write('system.performance', array());
|
||||
}
|
||||
|
||||
protected function read($name) {
|
||||
|
|
|
@ -24,8 +24,8 @@ class FileStorageTest extends ConfigStorageTestBase {
|
|||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->storage = new FileStorage();
|
||||
$this->invalidStorage = new FileStorage(array('directory' => $this->configDirectories[CONFIG_ACTIVE_DIRECTORY] . '/nonexisting'));
|
||||
$this->storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]);
|
||||
$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());
|
||||
|
|
|
@ -45,7 +45,7 @@ class Entity implements EntityInterface {
|
|||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $isCurrentRevision = TRUE;
|
||||
protected $isCurrentRevision = TRUE;
|
||||
|
||||
/**
|
||||
* Constructs a new entity object.
|
||||
|
@ -280,8 +280,12 @@ class Entity implements EntityInterface {
|
|||
/**
|
||||
* Implements Drupal\entity\EntityInterface::isCurrentRevision().
|
||||
*/
|
||||
public function isCurrentRevision() {
|
||||
return $this->isCurrentRevision;
|
||||
public function isCurrentRevision($new_value = NULL) {
|
||||
$return = $this->isCurrentRevision;
|
||||
if (isset($new_value)) {
|
||||
$this->isCurrentRevision = (bool) $new_value;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -211,8 +211,12 @@ interface EntityInterface {
|
|||
/**
|
||||
* Checks if this entity is the current revision.
|
||||
*
|
||||
* @param bool $new_value
|
||||
* (optional) A Boolean to (re)set the isCurrentRevision flag.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the entity is the current revision, FALSE otherwise.
|
||||
* TRUE if the entity is the current revision, FALSE otherwise. If
|
||||
* $new_value was passed, the previous value is returned.
|
||||
*/
|
||||
public function isCurrentRevision();
|
||||
public function isCurrentRevision($new_value = NULL);
|
||||
}
|
||||
|
|
|
@ -7,12 +7,20 @@
|
|||
|
||||
namespace Drupal\search\Tests;
|
||||
|
||||
use Drupal\simpletest\UnitTestBase;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the search_excerpt() function.
|
||||
*/
|
||||
class SearchExcerptTest extends UnitTestBase {
|
||||
class SearchExcerptTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('search');
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Search excerpt extraction',
|
||||
|
@ -21,11 +29,6 @@ class SearchExcerptTest extends UnitTestBase {
|
|||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
drupal_load('module', 'search');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests search_excerpt() with several simulated search keywords.
|
||||
*
|
||||
|
|
|
@ -726,6 +726,9 @@ abstract class TestBase {
|
|||
$GLOBALS['config_directories'][$type] = 'simpletest/' . substr($this->databasePrefix, 10) . '/config_' . $type;
|
||||
}
|
||||
|
||||
// Reset and create a new service container.
|
||||
$this->container = drupal_container(NULL, TRUE);
|
||||
|
||||
$this->configDirectories = array();
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
foreach ($GLOBALS['config_directories'] as $type => $path) {
|
||||
|
|
|
@ -674,6 +674,10 @@ abstract class WebTestBase extends TestBase {
|
|||
// Symfony\Component\HttpKernel\handle(), this kernel needs manual booting
|
||||
// as it is not used to handle a request.
|
||||
$this->kernel->boot();
|
||||
// The DrupalKernel does not update the container in drupal_container(), but
|
||||
// replaces it with a new object. We therefore need to replace the minimal
|
||||
// boostrap container that has been set up by TestBase::prepareEnvironment().
|
||||
$this->container = drupal_container();
|
||||
|
||||
// Reset/rebuild all data structures after enabling the modules.
|
||||
$this->resetAll();
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
namespace Drupal\system\Tests\Module;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Config\DatabaseStorage;
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
|
@ -99,7 +98,7 @@ abstract class ModuleTestBase extends WebTestBase {
|
|||
if (!is_dir($module_config_dir)) {
|
||||
return;
|
||||
}
|
||||
$module_file_storage = new FileStorage(array('directory' => $module_config_dir));
|
||||
$module_file_storage = new FileStorage($module_config_dir);
|
||||
$names = $module_file_storage->listAll();
|
||||
|
||||
// Verify that the config directory is not empty.
|
||||
|
|
|
@ -724,6 +724,8 @@ function system_schema() {
|
|||
);
|
||||
$schema['cache_bootstrap'] = $schema['cache'];
|
||||
$schema['cache_bootstrap']['description'] = 'Cache table for data required to bootstrap Drupal, may be routed to a shared memory cache.';
|
||||
$schema['cache_config'] = $schema['cache'];
|
||||
$schema['cache_config']['description'] = 'Cache table for configuration data.';
|
||||
$schema['cache_form'] = $schema['cache'];
|
||||
$schema['cache_form']['description'] = 'Cache table for the form system to store recently built forms and their storage data, to be used in subsequent page requests.';
|
||||
$schema['cache_page'] = $schema['cache'];
|
||||
|
@ -733,28 +735,6 @@ function system_schema() {
|
|||
$schema['cache_path'] = $schema['cache'];
|
||||
$schema['cache_path']['description'] = 'Cache table for path alias lookup.';
|
||||
|
||||
$schema['config'] = array(
|
||||
'description' => 'Default active store for the configuration system.',
|
||||
'fields' => array(
|
||||
'name' => array(
|
||||
'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'data' => array(
|
||||
'description' => 'The raw data for this configuration entry.',
|
||||
'type' => 'blob',
|
||||
'not null' => TRUE,
|
||||
'size' => 'big',
|
||||
'translatable' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('name'),
|
||||
);
|
||||
|
||||
|
||||
$schema['date_format_type'] = array(
|
||||
'description' => 'Stores configured date format types.',
|
||||
'fields' => array(
|
||||
|
@ -1567,33 +1547,63 @@ function system_update_8002() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds {config} table for new Configuration system.
|
||||
* Creates {cache_config} cache table for the new configuration system.
|
||||
*/
|
||||
function system_update_8003() {
|
||||
// @todo Temporary.
|
||||
if (db_table_exists('config')) {
|
||||
db_drop_table('config');
|
||||
}
|
||||
db_create_table('config', array(
|
||||
'description' => 'Default active store for the configuration system.',
|
||||
$spec = array(
|
||||
'description' => 'Cache table for configuration data.',
|
||||
'fields' => array(
|
||||
'name' => array(
|
||||
'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
|
||||
'cid' => array(
|
||||
'description' => 'Primary Key: Unique cache ID.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'data' => array(
|
||||
'description' => 'The raw data for this configuration entry.',
|
||||
'description' => 'A collection of data to cache.',
|
||||
'type' => 'blob',
|
||||
'not null' => TRUE,
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'translatable' => TRUE,
|
||||
),
|
||||
'expire' => array(
|
||||
'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'created' => array(
|
||||
'description' => 'A Unix timestamp indicating when the cache entry was created.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'serialized' => array(
|
||||
'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
|
||||
'type' => 'int',
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'tags' => array(
|
||||
'description' => 'Space-separated list of cache tags for this entry.',
|
||||
'type' => 'text',
|
||||
'size' => 'big',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'checksum' => array(
|
||||
'description' => 'The tag invalidation sum when this entry was saved.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'primary key' => array('name'),
|
||||
));
|
||||
'indexes' => array(
|
||||
'expire' => array('expire'),
|
||||
),
|
||||
'primary key' => array('cid'),
|
||||
);
|
||||
db_create_table('cache_config', $spec);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1673,7 +1683,7 @@ function system_update_8007() {
|
|||
foreach ($tables as $table) {
|
||||
// Assume we have a valid cache table if there is both 'cid' and 'data'
|
||||
// columns.
|
||||
if (db_field_exists($table, 'cid') && db_field_exists($table, 'data')) {
|
||||
if (db_field_exists($table, 'cid') && db_field_exists($table, 'data') && !db_field_exists($table, 'tags')) {
|
||||
db_add_field($table, 'tags', array(
|
||||
'description' => 'Space-separated list of cache tags for this entry.',
|
||||
'type' => 'text',
|
||||
|
|
|
@ -3509,7 +3509,7 @@ function system_cron() {
|
|||
*/
|
||||
function system_cache_flush() {
|
||||
// Do NOT flush the 'form' cache bin to retain in-progress form submissions.
|
||||
return array('bootstrap', 'cache', 'page', 'path');
|
||||
return array('bootstrap', 'config', 'cache', 'page', 'path');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue