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
|
* @see Drupal\Core\DrupalKernel
|
||||||
*
|
*
|
||||||
* @param $reset
|
* @param Symfony\Component\DependencyInjection\Container $new_container
|
||||||
* A new container instance to reset the Drupal container to.
|
* 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
|
* @return Symfony\Component\DependencyInjection\Container
|
||||||
* The instance of the Container used to set up and maintain object
|
* The instance of the Container used to set up and maintain object
|
||||||
* instances.
|
* 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
|
// 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
|
// which to reinitialize the stored objects, so a drupal_static_reset() call
|
||||||
// would leave Drupal in a nonfunctional state.
|
// would leave Drupal in a nonfunctional state.
|
||||||
static $container = NULL;
|
static $container = NULL;
|
||||||
if (isset($reset)) {
|
if ($rebuild) {
|
||||||
$container = $reset;
|
$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
|
// Return a ContainerBuilder instance with the bare essentials needed for any
|
||||||
// full bootstrap regardless of whether there will be a DrupalKernel involved.
|
// full bootstrap regardless of whether there will be a DrupalKernel involved.
|
||||||
// This will get merged with the full Kernel-built Container on normal page
|
// This will get merged with the full Kernel-built Container on normal page
|
||||||
// requests.
|
// requests.
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
// Register configuration storage class and options.
|
// Register active configuration storage.
|
||||||
// @todo The active store and its options need to be configurable.
|
$container
|
||||||
// Use either global $conf (recursion warning) or global $config, or a
|
->register('config.cachedstorage.storage', 'Drupal\Core\Config\FileStorage')
|
||||||
// bootstrap configuration *file* to allow to set/override this very
|
->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY));
|
||||||
// lowest of low level configuration.
|
// @todo Replace this with a cache.factory service plus 'config' argument.
|
||||||
$container->setParameter('config.storage.options', array(
|
$container
|
||||||
'connection' => 'default',
|
->register('cache.config')
|
||||||
'target' => 'default',
|
->setFactoryClass('Drupal\Core\Cache\CacheFactory')
|
||||||
));
|
->setFactoryMethod('get')
|
||||||
$container->register('config.storage', 'Drupal\Core\Config\DatabaseStorage')
|
->addArgument('config');
|
||||||
->addArgument('%config.storage.options%');
|
|
||||||
|
|
||||||
|
$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('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber');
|
||||||
$container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
|
$container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
|
||||||
->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf')));
|
->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf')));
|
||||||
// Register configuration object factory.
|
|
||||||
$container->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
|
$container->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
|
||||||
->addArgument(new Reference('config.storage'))
|
->addArgument(new Reference('config.storage'))
|
||||||
->addArgument(new Reference('dispatcher'));
|
->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;
|
return $container;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* Functions and interfaces for cache handling.
|
* Functions and interfaces for cache handling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Drupal\Core\Cache\CacheFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates and statically caches the correct class for a cache bin.
|
* 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.
|
// storage of a cache bin mid-request.
|
||||||
static $cache_objects;
|
static $cache_objects;
|
||||||
if (!isset($cache_objects[$bin])) {
|
if (!isset($cache_objects[$bin])) {
|
||||||
$cache_backends = cache_get_backends();
|
$cache_objects[$bin] = CacheFactory::get($bin);
|
||||||
$class = isset($cache_backends[$bin]) ? $cache_backends[$bin] : $cache_backends['cache'];
|
|
||||||
$cache_objects[$bin] = new $class($bin);
|
|
||||||
}
|
}
|
||||||
return $cache_objects[$bin];
|
return $cache_objects[$bin];
|
||||||
}
|
}
|
||||||
|
@ -53,17 +53,7 @@ function cache($bin = 'cache') {
|
||||||
* The list of tags to invalidate cache items for.
|
* The list of tags to invalidate cache items for.
|
||||||
*/
|
*/
|
||||||
function cache_invalidate(array $tags) {
|
function cache_invalidate(array $tags) {
|
||||||
foreach (cache_get_backends() as $bin => $class) {
|
foreach (CacheFactory::getBackends() as $bin => $class) {
|
||||||
cache($bin)->invalidateTags($tags);
|
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'.
|
* The extension type; e.g., 'module' or 'theme'.
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* The name of the module or theme to install default configuration for.
|
* 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) {
|
function config_install_default_config($type, $name) {
|
||||||
$config_dir = drupal_get_path($type, $name) . '/config';
|
$config_dir = drupal_get_path($type, $name) . '/config';
|
||||||
if (is_dir($config_dir)) {
|
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');
|
$target_storage = drupal_container()->get('config.storage');
|
||||||
$null_storage = new NullStorage();
|
$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 = '') {
|
function config_get_storage_names_with_prefix($prefix = '') {
|
||||||
return drupal_container()->get('config.storage')->listAll($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() {
|
function config_import() {
|
||||||
// Retrieve a list of differences between staging and the active store.
|
// 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');
|
$target_storage = drupal_container()->get('config.storage');
|
||||||
|
|
||||||
$config_changes = config_sync_get_changes($source_storage, $target_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() {
|
function config_export() {
|
||||||
// Retrieve a list of differences between the active store and staging.
|
// Retrieve a list of differences between the active store and staging.
|
||||||
$source_storage = drupal_container()->get('config.storage');
|
$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);
|
$config_changes = config_sync_get_changes($source_storage, $target_storage);
|
||||||
if (empty($config_changes)) {
|
if (empty($config_changes)) {
|
||||||
|
|
|
@ -5,6 +5,8 @@ use Drupal\Core\Database\Database;
|
||||||
use Drupal\Core\Database\Install\TaskException;
|
use Drupal\Core\Database\Install\TaskException;
|
||||||
use Drupal\Core\Language\Language;
|
use Drupal\Core\Language\Language;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
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/module.inc';
|
||||||
include_once DRUPAL_ROOT . '/core/includes/session.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.
|
// Set up $language, so t() caller functions will still work.
|
||||||
drupal_language_initialize();
|
drupal_language_initialize();
|
||||||
|
|
||||||
|
@ -316,7 +358,6 @@ function install_begin_request(&$install_state) {
|
||||||
|
|
||||||
// Check existing settings.php.
|
// Check existing settings.php.
|
||||||
$install_state['database_verified'] = install_verify_database_settings();
|
$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'];
|
$install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified'];
|
||||||
|
|
||||||
if ($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.
|
// Add the config directories to settings.php.
|
||||||
drupal_install_config_directories();
|
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
|
// 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
|
// 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
|
// 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);
|
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) {
|
foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) {
|
||||||
// This should never fail, since if the config directory was specified in
|
// This should never fail, since if the config directory was specified in
|
||||||
// settings.php it will have already been created and verified earlier, and
|
// 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
|
* Checks whether a config directory name is defined, and if so, whether it
|
||||||
* exists and is writable.
|
* 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
|
* since the installer would create the config directory too early in the
|
||||||
* installation process otherwise (e.g., when only visiting install.php when
|
* installation process otherwise (e.g., when only visiting install.php when
|
||||||
* there is a settings.php already, but not actually executing the installation).
|
* 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])) {
|
if (!isset($config_directories[$type])) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
$config_directory = config_get_config_directory($type);
|
// config_get_config_directory() throws an exception when the passed $type
|
||||||
if (is_dir($config_directory) && is_writable($config_directory)) {
|
// does not exist in $config_directories. This can happen if there is a
|
||||||
return TRUE;
|
// 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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Drupal\Component\Graph\Graph;
|
use Drupal\Component\Graph\Graph;
|
||||||
use Drupal\Core\Config\DatabaseStorage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all the modules that have been enabled in the system table.
|
* 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);
|
$module_list = array_keys($module_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
$storage = new DatabaseStorage();
|
$storage = drupal_container()->get('config.storage');
|
||||||
foreach ($module_list as $module) {
|
foreach ($module_list as $module) {
|
||||||
// Uninstall the module.
|
// Uninstall the module.
|
||||||
module_load_install($module);
|
module_load_install($module);
|
||||||
|
|
|
@ -1056,7 +1056,7 @@ function update_variables_to_config($config_name, array $variable_map) {
|
||||||
$module = strtok($config_name, '.');
|
$module = strtok($config_name, '.');
|
||||||
|
|
||||||
// Load and set default configuration values.
|
// 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)) {
|
if (!$file->exists($config_name)) {
|
||||||
throw new ConfigException("Default configuration file $config_name for $module extension not found but is required to exist.");
|
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;
|
namespace Drupal\Core\Config;
|
||||||
|
|
||||||
use Drupal\Core\Database\Database;
|
use Drupal\Core\Database\Database;
|
||||||
|
use Drupal\Core\Database\Connection;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,31 +17,49 @@ use Exception;
|
||||||
class DatabaseStorage implements StorageInterface {
|
class DatabaseStorage implements StorageInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database connection options for this storage controller.
|
* The database connection.
|
||||||
*
|
*
|
||||||
* - connection: The connection key to use.
|
* @var Drupal\Core\Database\Connection
|
||||||
* - target: The target on the connection to use.
|
*/
|
||||||
|
protected $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database table name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional database connection options to use in queries.
|
||||||
*
|
*
|
||||||
* @var array
|
* @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()) {
|
public function __construct(Connection $connection, $table, array $options = array()) {
|
||||||
$options += array(
|
$this->connection = $connection;
|
||||||
'connection' => 'default',
|
$this->table = $table;
|
||||||
'target' => 'default',
|
|
||||||
);
|
|
||||||
$this->options = $options;
|
$this->options = $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database connection to use.
|
* Implements Drupal\Core\Config\StorageInterface::exists().
|
||||||
*/
|
*/
|
||||||
protected function getConnection() {
|
public function exists($name) {
|
||||||
return Database::getConnection($this->options['target'], $this->options['connection']);
|
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,
|
// read without actually having the database available. In this case,
|
||||||
// catch the exception and just return an empty array so the caller can
|
// catch the exception and just return an empty array so the caller can
|
||||||
// handle it if need be.
|
// handle it if need be.
|
||||||
// @todo Remove this and use appropriate config.storage service definition
|
|
||||||
// in the installer instead.
|
|
||||||
try {
|
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) {
|
if ($raw !== FALSE) {
|
||||||
$data = $this->decode($raw);
|
$data = $this->decode($raw);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +96,7 @@ class DatabaseStorage implements StorageInterface {
|
||||||
public function write($name, array $data) {
|
public function write($name, array $data) {
|
||||||
$data = $this->encode($data);
|
$data = $this->encode($data);
|
||||||
$options = array('return' => Database::RETURN_AFFECTED) + $this->options;
|
$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))
|
->key(array('name' => $name))
|
||||||
->fields(array('data' => $data))
|
->fields(array('data' => $data))
|
||||||
->execute();
|
->execute();
|
||||||
|
@ -94,7 +111,7 @@ class DatabaseStorage implements StorageInterface {
|
||||||
*/
|
*/
|
||||||
public function delete($name) {
|
public function delete($name) {
|
||||||
$options = array('return' => Database::RETURN_AFFECTED) + $this->options;
|
$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)
|
->condition('name', $name)
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
@ -107,7 +124,7 @@ class DatabaseStorage implements StorageInterface {
|
||||||
*/
|
*/
|
||||||
public function rename($name, $new_name) {
|
public function rename($name, $new_name) {
|
||||||
$options = array('return' => Database::RETURN_AFFECTED) + $this->options;
|
$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))
|
->fields(array('name' => $new_name))
|
||||||
->condition('name', $name)
|
->condition('name', $name)
|
||||||
->execute();
|
->execute();
|
||||||
|
@ -139,7 +156,7 @@ class DatabaseStorage implements StorageInterface {
|
||||||
* Only thrown in case $this->options['throw_exception'] is TRUE.
|
* Only thrown in case $this->options['throw_exception'] is TRUE.
|
||||||
*/
|
*/
|
||||||
public function listAll($prefix = '') {
|
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) . '%',
|
':name' => db_like($prefix) . '%',
|
||||||
), $this->options)->fetchCol();
|
), $this->options)->fetchCol();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,11 @@ use Symfony\Component\Yaml\Parser;
|
||||||
class FileStorage implements StorageInterface {
|
class FileStorage implements StorageInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration options for this storage controller.
|
* The filesystem path for configuration objects.
|
||||||
*
|
*
|
||||||
* - directory: The filesystem path for configuration objects.
|
* @var string
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected $options;
|
protected $directory = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A shared YAML dumper instance.
|
* A shared YAML dumper instance.
|
||||||
|
@ -39,13 +37,13 @@ class FileStorage implements StorageInterface {
|
||||||
protected $parser;
|
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()) {
|
public function __construct($directory) {
|
||||||
if (!isset($options['directory'])) {
|
$this->directory = $directory;
|
||||||
$options['directory'] = config_get_config_directory();
|
|
||||||
}
|
|
||||||
$this->options = $options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,7 +53,7 @@ class FileStorage implements StorageInterface {
|
||||||
* The path to the configuration file.
|
* The path to the configuration file.
|
||||||
*/
|
*/
|
||||||
public function getFilePath($name) {
|
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) {
|
public function delete($name) {
|
||||||
if (!$this->exists($name)) {
|
if (!$this->exists($name)) {
|
||||||
if (!file_exists($this->options['directory'])) {
|
if (!file_exists($this->directory)) {
|
||||||
throw new StorageException($this->options['directory'] . '/ not found.');
|
throw new StorageException($this->directory . '/ not found.');
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -188,11 +186,11 @@ class FileStorage implements StorageInterface {
|
||||||
public function listAll($prefix = '') {
|
public function listAll($prefix = '') {
|
||||||
// glob() silently ignores the error of a non-existing search directory,
|
// glob() silently ignores the error of a non-existing search directory,
|
||||||
// even with the GLOB_ERR flag.
|
// even with the GLOB_ERR flag.
|
||||||
if (!file_exists($this->options['directory'])) {
|
if (!file_exists($this->directory)) {
|
||||||
throw new StorageException($this->options['directory'] . '/ not found.');
|
throw new StorageException($this->directory . '/ not found.');
|
||||||
}
|
}
|
||||||
$extension = '.' . self::getFileExtension();
|
$extension = '.' . self::getFileExtension();
|
||||||
$files = glob($this->options['directory'] . '/' . $prefix . '*' . $extension);
|
$files = glob($this->directory . '/' . $prefix . '*' . $extension);
|
||||||
$clean_name = function ($value) use ($extension) {
|
$clean_name = function ($value) use ($extension) {
|
||||||
return basename($value, $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.
|
* This also can be used for testing purposes.
|
||||||
*/
|
*/
|
||||||
class NullStorage implements StorageInterface {
|
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 {
|
interface StorageInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the storage controller.
|
* Returns whether a configuration object exists.
|
||||||
*
|
*
|
||||||
* @param array $options
|
* @param string $name
|
||||||
* An associative array containing configuration options specific to the
|
* The name of a configuration object to test.
|
||||||
* storage controller.
|
*
|
||||||
|
* @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.
|
* 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
|
// Configuration objects do not have a schema. Extract all key names from
|
||||||
// class properties.
|
// class properties.
|
||||||
$class_info = new \ReflectionClass($entity);
|
$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();
|
$name = $property->getName();
|
||||||
$config->set($name, $entity->$name);
|
$config->set($name, $entity->$name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
namespace Drupal\config\Tests;
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
use Drupal\Core\Config\DatabaseStorage;
|
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +25,7 @@ class ConfigCRUDTest extends WebTestBase {
|
||||||
* Tests CRUD operations.
|
* Tests CRUD operations.
|
||||||
*/
|
*/
|
||||||
function testCRUD() {
|
function testCRUD() {
|
||||||
$storage = new DatabaseStorage();
|
$storage = $this->container->get('config.storage');
|
||||||
$name = 'config_test.crud';
|
$name = 'config_test.crud';
|
||||||
|
|
||||||
$config = config($name);
|
$config = config($name);
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
namespace Drupal\config\Tests;
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
use Drupal\Core\Config\DatabaseStorage;
|
|
||||||
use Drupal\Core\Config\FileStorage;
|
use Drupal\Core\Config\FileStorage;
|
||||||
use Drupal\simpletest\WebTestBase;
|
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.
|
* Tests setting, writing, and reading of a configuration setting.
|
||||||
*/
|
*/
|
||||||
function testReadWriteConfig() {
|
function testReadWriteConfig() {
|
||||||
$database_storage = new DatabaseStorage();
|
$storage = $this->container->get('config.storage');
|
||||||
|
|
||||||
$name = 'foo.bar';
|
$name = 'foo.bar';
|
||||||
$key = 'foo';
|
$key = 'foo';
|
||||||
|
@ -67,8 +62,8 @@ class ConfigFileContentTest extends WebTestBase {
|
||||||
$this->assertEqual($config->get(), array(), t('New config object is empty.'));
|
$this->assertEqual($config->get(), array(), t('New config object is empty.'));
|
||||||
|
|
||||||
// Verify nothing was saved.
|
// Verify nothing was saved.
|
||||||
$db_data = $database_storage->read($name);
|
$data = $storage->read($name);
|
||||||
$this->assertIdentical($db_data, FALSE);
|
$this->assertIdentical($data, FALSE);
|
||||||
|
|
||||||
// Add a top level value
|
// Add a top level value
|
||||||
$config = config($name);
|
$config = config($name);
|
||||||
|
@ -94,8 +89,8 @@ class ConfigFileContentTest extends WebTestBase {
|
||||||
$config->save();
|
$config->save();
|
||||||
|
|
||||||
// Verify the database entry exists.
|
// Verify the database entry exists.
|
||||||
$db_data = $database_storage->read($name);
|
$data = $storage->read($name);
|
||||||
$this->assertTrue($db_data);
|
$this->assertTrue($data);
|
||||||
|
|
||||||
// Read top level value
|
// Read top level value
|
||||||
$config = config($name);
|
$config = config($name);
|
||||||
|
@ -152,27 +147,27 @@ class ConfigFileContentTest extends WebTestBase {
|
||||||
$config->set($key, $value)->save();
|
$config->set($key, $value)->save();
|
||||||
|
|
||||||
// Verify the database entry exists from a chained save.
|
// Verify the database entry exists from a chained save.
|
||||||
$db_data = $database_storage->read($chained_name);
|
$data = $storage->read($chained_name);
|
||||||
$this->assertEqual($db_data, $config->get());
|
$this->assertEqual($data, $config->get());
|
||||||
|
|
||||||
// Get file listing for all files starting with 'foo'. Should return
|
// Get file listing for all files starting with 'foo'. Should return
|
||||||
// two elements.
|
// two elements.
|
||||||
$files = $database_storage->listAll('foo');
|
$files = $storage->listAll('foo');
|
||||||
$this->assertEqual(count($files), 2, 'Two files listed with the prefix \'foo\'.');
|
$this->assertEqual(count($files), 2, 'Two files listed with the prefix \'foo\'.');
|
||||||
|
|
||||||
// Get file listing for all files starting with 'biff'. Should return
|
// Get file listing for all files starting with 'biff'. Should return
|
||||||
// one element.
|
// one element.
|
||||||
$files = $database_storage->listAll('biff');
|
$files = $storage->listAll('biff');
|
||||||
$this->assertEqual(count($files), 1, 'One file listed with the prefix \'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
|
// Get file listing for all files starting with 'foo.bar'. Should return
|
||||||
// one element.
|
// 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\'.');
|
$this->assertEqual(count($files), 1, 'One file listed with the prefix \'foo.bar\'.');
|
||||||
|
|
||||||
// Get file listing for all files starting with 'bar'. Should return
|
// Get file listing for all files starting with 'bar'. Should return
|
||||||
// an empty array.
|
// an empty array.
|
||||||
$files = $database_storage->listAll('bar');
|
$files = $storage->listAll('bar');
|
||||||
$this->assertEqual($files, array(), 'No files listed with the prefix \'bar\'.');
|
$this->assertEqual($files, array(), 'No files listed with the prefix \'bar\'.');
|
||||||
|
|
||||||
// Delete the configuration.
|
// Delete the configuration.
|
||||||
|
@ -180,8 +175,8 @@ class ConfigFileContentTest extends WebTestBase {
|
||||||
$config->delete();
|
$config->delete();
|
||||||
|
|
||||||
// Verify the database entry no longer exists.
|
// Verify the database entry no longer exists.
|
||||||
$db_data = $database_storage->read($name);
|
$data = $storage->read($name);
|
||||||
$this->assertIdentical($db_data, FALSE);
|
$this->assertIdentical($data, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,7 +200,7 @@ class ConfigFileContentTest extends WebTestBase {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Encode and write, and reload and decode the configuration data.
|
// 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);
|
$filestorage->write($name, $config_data);
|
||||||
$config_parsed = $filestorage->read($name);
|
$config_parsed = $filestorage->read($name);
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
namespace Drupal\config\Tests;
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
use Drupal\Core\Config\DatabaseStorage;
|
|
||||||
use Drupal\Core\Config\FileStorage;
|
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,8 +62,8 @@ class ConfigImportTest extends WebTestBase {
|
||||||
function testDeleted() {
|
function testDeleted() {
|
||||||
$name = 'config_test.system';
|
$name = 'config_test.system';
|
||||||
$dynamic_name = 'config_test.dynamic.default';
|
$dynamic_name = 'config_test.dynamic.default';
|
||||||
$active_storage = new DatabaseStorage();
|
$storage = $this->container->get('config.storage');
|
||||||
$staging_storage = new FileStorage(array('directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY)));
|
$staging = $this->container->get('config.storage.staging');
|
||||||
|
|
||||||
// Verify the default configuration values exist.
|
// Verify the default configuration values exist.
|
||||||
$config = config($name);
|
$config = config($name);
|
||||||
|
@ -77,15 +75,15 @@ class ConfigImportTest extends WebTestBase {
|
||||||
config_export();
|
config_export();
|
||||||
|
|
||||||
// Delete the configuration objects from the staging directory.
|
// Delete the configuration objects from the staging directory.
|
||||||
$staging_storage->delete($name);
|
$staging->delete($name);
|
||||||
$staging_storage->delete($dynamic_name);
|
$staging->delete($dynamic_name);
|
||||||
|
|
||||||
// Import.
|
// Import.
|
||||||
config_import();
|
config_import();
|
||||||
|
|
||||||
// Verify the values have disappeared.
|
// Verify the values have disappeared.
|
||||||
$this->assertIdentical($active_storage->read($name), FALSE);
|
$this->assertIdentical($storage->read($name), FALSE);
|
||||||
$this->assertIdentical($active_storage->read($dynamic_name), FALSE);
|
$this->assertIdentical($storage->read($dynamic_name), FALSE);
|
||||||
|
|
||||||
$config = config($name);
|
$config = config($name);
|
||||||
$this->assertIdentical($config->get('foo'), NULL);
|
$this->assertIdentical($config->get('foo'), NULL);
|
||||||
|
@ -99,6 +97,9 @@ class ConfigImportTest extends WebTestBase {
|
||||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
|
$this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
|
||||||
$this->assertTrue(isset($GLOBALS['hook_config_test']['predelete']));
|
$this->assertTrue(isset($GLOBALS['hook_config_test']['predelete']));
|
||||||
$this->assertTrue(isset($GLOBALS['hook_config_test']['delete']));
|
$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() {
|
function testNew() {
|
||||||
$name = 'config_test.new';
|
$name = 'config_test.new';
|
||||||
$dynamic_name = 'config_test.dynamic.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.
|
// Export.
|
||||||
config_export();
|
config_export();
|
||||||
|
|
||||||
// Verify the configuration to create does not exist yet.
|
// Verify the configuration to create does not exist yet.
|
||||||
$this->assertIdentical($staging_storage->exists($name), FALSE, $name . ' not found.');
|
$this->assertIdentical($storage->exists($name), FALSE, $name . ' not found.');
|
||||||
$this->assertIdentical($staging_storage->exists($dynamic_name), FALSE, $dynamic_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.
|
// Create new configuration objects in the staging directory.
|
||||||
$original_name_data = array(
|
$original_name_data = array(
|
||||||
'add_me' => 'new value',
|
'add_me' => 'new value',
|
||||||
);
|
);
|
||||||
$staging_storage->write($name, $original_name_data);
|
$staging->write($name, $original_name_data);
|
||||||
$original_dynamic_data = array(
|
$original_dynamic_data = array(
|
||||||
'id' => 'new',
|
'id' => 'new',
|
||||||
'label' => 'New',
|
'label' => 'New',
|
||||||
|
'langcode' => 'und',
|
||||||
|
'style' => '',
|
||||||
|
'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651',
|
||||||
);
|
);
|
||||||
$staging_storage->write($dynamic_name, $original_dynamic_data);
|
$staging->write($dynamic_name, $original_dynamic_data);
|
||||||
$this->assertIdentical($staging_storage->exists($name), TRUE, $name . ' found.');
|
$this->assertIdentical($staging->exists($name), TRUE, $name . ' found.');
|
||||||
$this->assertIdentical($staging_storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
$this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
|
||||||
|
|
||||||
// Import.
|
// Import.
|
||||||
config_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']['update']));
|
||||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
|
$this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
|
||||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
|
$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() {
|
function testUpdated() {
|
||||||
$name = 'config_test.system';
|
$name = 'config_test.system';
|
||||||
$dynamic_name = 'config_test.dynamic.default';
|
$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.
|
// Export.
|
||||||
config_export();
|
config_export();
|
||||||
|
|
||||||
// Verify that the configuration objects to import exist.
|
// Verify that the configuration objects to import exist.
|
||||||
$this->assertIdentical($staging_storage->exists($name), TRUE, $name . ' found.');
|
$this->assertIdentical($storage->exists($name), TRUE, $name . ' found.');
|
||||||
$this->assertIdentical($staging_storage->exists($dynamic_name), TRUE, $dynamic_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
|
// Replace the file content of the existing configuration objects in the
|
||||||
// staging directory.
|
// staging directory.
|
||||||
$original_name_data = array(
|
$original_name_data = array(
|
||||||
'foo' => 'beer',
|
'foo' => 'beer',
|
||||||
);
|
);
|
||||||
$staging_storage->write($name, $original_name_data);
|
$staging->write($name, $original_name_data);
|
||||||
$original_dynamic_data = array(
|
$original_dynamic_data = $staging->read($dynamic_name);
|
||||||
'id' => 'default',
|
$original_dynamic_data['label'] = 'Updated';
|
||||||
'label' => 'Updated',
|
$staging->write($dynamic_name, $original_dynamic_data);
|
||||||
);
|
|
||||||
$staging_storage->write($dynamic_name, $original_dynamic_data);
|
|
||||||
|
|
||||||
// Verify the active store still returns the default values.
|
// Verify the active store still returns the default values.
|
||||||
$config = config($name);
|
$config = config($name);
|
||||||
|
@ -190,8 +203,8 @@ class ConfigImportTest extends WebTestBase {
|
||||||
$this->assertIdentical($config->get('label'), 'Updated');
|
$this->assertIdentical($config->get('label'), 'Updated');
|
||||||
|
|
||||||
// Verify that the original file content is still the same.
|
// Verify that the original file content is still the same.
|
||||||
$this->assertIdentical($staging_storage->read($name), $original_name_data);
|
$this->assertIdentical($staging->read($name), $original_name_data);
|
||||||
$this->assertIdentical($staging_storage->read($dynamic_name), $original_dynamic_data);
|
$this->assertIdentical($staging->read($dynamic_name), $original_dynamic_data);
|
||||||
|
|
||||||
// Verify that appropriate module API hooks have been invoked.
|
// Verify that appropriate module API hooks have been invoked.
|
||||||
$this->assertTrue(isset($GLOBALS['hook_config_test']['load']));
|
$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->assertTrue(isset($GLOBALS['hook_config_test']['update']));
|
||||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
|
$this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
|
||||||
$this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
|
$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() {
|
function testCRUD() {
|
||||||
$name = 'config_test.storage';
|
$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.
|
// Reading a non-existing name returns FALSE.
|
||||||
$data = $this->storage->read($name);
|
$data = $this->storage->read($name);
|
||||||
$this->assertIdentical($data, FALSE);
|
$this->assertIdentical($data, FALSE);
|
||||||
|
@ -51,9 +54,13 @@ abstract class ConfigStorageTestBase extends WebTestBase {
|
||||||
$data = array('foo' => 'bar');
|
$data = array('foo' => 'bar');
|
||||||
$result = $this->storage->write($name, $data);
|
$result = $this->storage->write($name, $data);
|
||||||
$this->assertIdentical($result, TRUE);
|
$this->assertIdentical($result, TRUE);
|
||||||
|
|
||||||
$raw_data = $this->read($name);
|
$raw_data = $this->read($name);
|
||||||
$this->assertIdentical($raw_data, $data);
|
$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.
|
// Writing the identical data again still returns TRUE.
|
||||||
$result = $this->storage->write($name, $data);
|
$result = $this->storage->write($name, $data);
|
||||||
$this->assertIdentical($result, TRUE);
|
$this->assertIdentical($result, TRUE);
|
||||||
|
|
|
@ -23,8 +23,34 @@ class DatabaseStorageTest extends ConfigStorageTestBase {
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
parent::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) {
|
protected function read($name) {
|
||||||
|
|
|
@ -24,8 +24,8 @@ class FileStorageTest extends ConfigStorageTestBase {
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->storage = new FileStorage();
|
$this->storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]);
|
||||||
$this->invalidStorage = new FileStorage(array('directory' => $this->configDirectories[CONFIG_ACTIVE_DIRECTORY] . '/nonexisting'));
|
$this->invalidStorage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY] . '/nonexisting');
|
||||||
|
|
||||||
// FileStorage::listAll() requires other configuration data to exist.
|
// FileStorage::listAll() requires other configuration data to exist.
|
||||||
$this->storage->write('system.performance', config('system.performance')->get());
|
$this->storage->write('system.performance', config('system.performance')->get());
|
||||||
|
|
|
@ -45,7 +45,7 @@ class Entity implements EntityInterface {
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $isCurrentRevision = TRUE;
|
protected $isCurrentRevision = TRUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new entity object.
|
* Constructs a new entity object.
|
||||||
|
@ -280,8 +280,12 @@ class Entity implements EntityInterface {
|
||||||
/**
|
/**
|
||||||
* Implements Drupal\entity\EntityInterface::isCurrentRevision().
|
* Implements Drupal\entity\EntityInterface::isCurrentRevision().
|
||||||
*/
|
*/
|
||||||
public function isCurrentRevision() {
|
public function isCurrentRevision($new_value = NULL) {
|
||||||
return $this->isCurrentRevision;
|
$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.
|
* Checks if this entity is the current revision.
|
||||||
*
|
*
|
||||||
|
* @param bool $new_value
|
||||||
|
* (optional) A Boolean to (re)set the isCurrentRevision flag.
|
||||||
|
*
|
||||||
* @return bool
|
* @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;
|
namespace Drupal\search\Tests;
|
||||||
|
|
||||||
use Drupal\simpletest\UnitTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the search_excerpt() function.
|
* 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() {
|
public static function getInfo() {
|
||||||
return array(
|
return array(
|
||||||
'name' => 'Search excerpt extraction',
|
'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.
|
* 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;
|
$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();
|
$this->configDirectories = array();
|
||||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||||
foreach ($GLOBALS['config_directories'] as $type => $path) {
|
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
|
// Symfony\Component\HttpKernel\handle(), this kernel needs manual booting
|
||||||
// as it is not used to handle a request.
|
// as it is not used to handle a request.
|
||||||
$this->kernel->boot();
|
$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.
|
// Reset/rebuild all data structures after enabling the modules.
|
||||||
$this->resetAll();
|
$this->resetAll();
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
namespace Drupal\system\Tests\Module;
|
namespace Drupal\system\Tests\Module;
|
||||||
|
|
||||||
use Drupal\Core\Database\Database;
|
use Drupal\Core\Database\Database;
|
||||||
use Drupal\Core\Config\DatabaseStorage;
|
|
||||||
use Drupal\Core\Config\FileStorage;
|
use Drupal\Core\Config\FileStorage;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
|
@ -99,7 +98,7 @@ abstract class ModuleTestBase extends WebTestBase {
|
||||||
if (!is_dir($module_config_dir)) {
|
if (!is_dir($module_config_dir)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$module_file_storage = new FileStorage(array('directory' => $module_config_dir));
|
$module_file_storage = new FileStorage($module_config_dir);
|
||||||
$names = $module_file_storage->listAll();
|
$names = $module_file_storage->listAll();
|
||||||
|
|
||||||
// Verify that the config directory is not empty.
|
// Verify that the config directory is not empty.
|
||||||
|
|
|
@ -724,6 +724,8 @@ function system_schema() {
|
||||||
);
|
);
|
||||||
$schema['cache_bootstrap'] = $schema['cache'];
|
$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_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'] = $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_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'];
|
$schema['cache_page'] = $schema['cache'];
|
||||||
|
@ -733,28 +735,6 @@ function system_schema() {
|
||||||
$schema['cache_path'] = $schema['cache'];
|
$schema['cache_path'] = $schema['cache'];
|
||||||
$schema['cache_path']['description'] = 'Cache table for path alias lookup.';
|
$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(
|
$schema['date_format_type'] = array(
|
||||||
'description' => 'Stores configured date format types.',
|
'description' => 'Stores configured date format types.',
|
||||||
'fields' => array(
|
'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() {
|
function system_update_8003() {
|
||||||
// @todo Temporary.
|
$spec = array(
|
||||||
if (db_table_exists('config')) {
|
'description' => 'Cache table for configuration data.',
|
||||||
db_drop_table('config');
|
|
||||||
}
|
|
||||||
db_create_table('config', array(
|
|
||||||
'description' => 'Default active store for the configuration system.',
|
|
||||||
'fields' => array(
|
'fields' => array(
|
||||||
'name' => array(
|
'cid' => array(
|
||||||
'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
|
'description' => 'Primary Key: Unique cache ID.',
|
||||||
'type' => 'varchar',
|
'type' => 'varchar',
|
||||||
'length' => 255,
|
'length' => 255,
|
||||||
'not null' => TRUE,
|
'not null' => TRUE,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
),
|
),
|
||||||
'data' => array(
|
'data' => array(
|
||||||
'description' => 'The raw data for this configuration entry.',
|
'description' => 'A collection of data to cache.',
|
||||||
'type' => 'blob',
|
'type' => 'blob',
|
||||||
'not null' => TRUE,
|
'not null' => FALSE,
|
||||||
'size' => 'big',
|
'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) {
|
foreach ($tables as $table) {
|
||||||
// Assume we have a valid cache table if there is both 'cid' and 'data'
|
// Assume we have a valid cache table if there is both 'cid' and 'data'
|
||||||
// columns.
|
// 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(
|
db_add_field($table, 'tags', array(
|
||||||
'description' => 'Space-separated list of cache tags for this entry.',
|
'description' => 'Space-separated list of cache tags for this entry.',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
|
|
@ -3509,7 +3509,7 @@ function system_cron() {
|
||||||
*/
|
*/
|
||||||
function system_cache_flush() {
|
function system_cache_flush() {
|
||||||
// Do NOT flush the 'form' cache bin to retain in-progress form submissions.
|
// 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