diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index a15710f..3a195a2 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -686,13 +686,14 @@ function drupal_settings_initialize() { global $base_url, $base_path, $base_root, $script_path; // Export these settings.php variables to the global namespace. - global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url, $config_directories; + global $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url, $config_directories; $conf = array(); // Make conf_path() available as local variable in settings.php. $conf_path = conf_path(); if (file_exists(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) { include_once DRUPAL_ROOT . '/' . $conf_path . '/settings.php'; + drupal_container()->setParameter('database.info', isset($databases) ? $databases : array()); } $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on'; @@ -2133,14 +2134,14 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { _drupal_bootstrap_configuration(); break; - case DRUPAL_BOOTSTRAP_PAGE_CACHE: - _drupal_bootstrap_page_cache(); - break; - case DRUPAL_BOOTSTRAP_DATABASE: _drupal_bootstrap_database(); break; + case DRUPAL_BOOTSTRAP_PAGE_CACHE: + _drupal_bootstrap_page_cache(); + break; + case DRUPAL_BOOTSTRAP_VARIABLES: _drupal_bootstrap_variables(); break; @@ -2242,11 +2243,11 @@ function _drupal_bootstrap_configuration() { drupal_environment_initialize(); // Start a page timer: timer_start('page'); + // Activate the class loader. + drupal_classloader(); // Initialize the configuration, including variables from settings.php. drupal_settings_initialize(); - // Activate the class loader. - drupal_classloader(); // Load the procedural configuration system helper functions. require_once DRUPAL_ROOT . '/core/includes/config.inc'; @@ -2316,7 +2317,10 @@ function _drupal_bootstrap_database() { // Redirect the user to the installation script if Drupal has not been // installed yet (i.e., if no $databases array has been defined in the // settings.php file) and we are not already installing. - if (empty($GLOBALS['databases']) && !drupal_installation_attempted()) { + $container = drupal_container(); + $databases = $container->getParameter('database.info'); + + if (!$databases && !drupal_installation_attempted()) { include_once DRUPAL_ROOT . '/core/includes/install.inc'; install_goto('core/install.php'); } @@ -2330,7 +2334,7 @@ function _drupal_bootstrap_database() { $test_info['test_run_id'] = $test_prefix; $test_info['in_child_site'] = TRUE; - foreach ($GLOBALS['databases']['default'] as &$value) { + foreach ($databases['default'] as &$value) { // Extract the current default database prefix. if (!isset($value['prefix'])) { $current_prefix = ''; @@ -2347,6 +2351,7 @@ function _drupal_bootstrap_database() { 'default' => $current_prefix . $test_prefix, ); } + $container->setParameter('database.info', $databases); } // Initialize the database system. Note that the connection @@ -2404,20 +2409,22 @@ function drupal_get_bootstrap_phase() { * * @see Drupal\Core\DrupalKernel * - * @param $reset - * A new container instance to reset the Drupal container to. + * @param $new_container + * A new container instance to store. + * @param $rebuild + * TRUE to build a new minimal container. * * @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 ($new_container || $rebuild) { + $container = $new_container; } elseif (!isset($container)) { // Return a ContainerBuilder instance with the bare essentials needed for any @@ -2445,6 +2452,22 @@ function drupal_container(Container $reset = NULL) { $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') ->addArgument(new Reference('config.storage')) ->addArgument(new Reference('dispatcher')); + // This will be overridden by settings.php in drupal_settings_initialize(). + $container->setParameter('database.info', array()); + $container->register('database', 'Drupal\Core\Database\Connection') + ->setFactoryClass('Drupal\Core\Database\Database') + ->setFactoryMethod('getConnection') + ->addArgument('default') + ->addArgument(NULL) + ->addArgument('%database.info%'); + $container->register('database.slave', 'Drupal\Core\Database\Connection') + ->setFactoryClass('Drupal\Core\Database\Database') + ->setFactoryMethod('getConnection') + ->addArgument('slave') + ->addArgument(NULL) + ->addArgument('%database.info%'); + $container->register('cache', 'Drupal\Core\Cache\DatabaseBackend') + ->addArgument(new Reference('database')); } return $container; } diff --git a/core/includes/cache.inc b/core/includes/cache.inc index 73bb05f..250ed3c 100644 --- a/core/includes/cache.inc +++ b/core/includes/cache.inc @@ -23,18 +23,22 @@ * * @see Drupal\Core\Cache\CacheBackendInterface */ -function cache($bin = 'cache') { +function cache($bin = 'cache', $reset = FALSE) { + // We do not use drupal_static() here because we do not want to change the + // storage of a cache bin mid-request. However, testing needs a reset. + static $cache_objects; + if ($reset) { + $cache_objects = array(); + return; + } // Temporary backwards compatibiltiy layer, allow old style prefixed cache // bin names to be passed as arguments. $bin = str_replace('cache_', '', $bin); - // We do not use drupal_static() here because we do not want to change the - // 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); + $container = drupal_container(); + $service = $container->has("cache.$bin") ? "cache.$bin" : 'cache'; + $cache_objects[$bin] = $container->get($service)->bin($bin); } return $cache_objects[$bin]; } @@ -65,5 +69,12 @@ function cache_invalidate(array $tags) { * 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')); + $container = drupal_container(); + $cache_services = array_filter($container->getServiceIds(), function ($value) { return substr($value, 0, 6) == 'cache.';}); + $cache_services[] = 'cache'; + $backends = array(); + foreach ($cache_services as $service) { + $backends[$service] = get_class($container->get($service)); + } + return $backends; } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index b0825b8..5c5e9c1 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -875,8 +875,8 @@ function install_verify_completed_task() { * Verifies that settings.php specifies a valid database connection. */ function install_verify_database_settings() { - global $databases; - if (!empty($databases) && install_verify_pdo()) { + $container = drupal_container(); + if (($databases = $container->getParameter('database.info')) && install_verify_pdo()) { $database = $databases['default']['default']; drupal_static_reset('conf_path'); $settings_file = './' . conf_path(FALSE) . '/settings.php'; @@ -1016,7 +1016,6 @@ function install_database_errors($database, $settings_file) { if (Database::isActiveConnection()) { Database::closeConnection(); } - Database::parseConnectionInfo(); try { db_run_tasks($driver); diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php index 2140960..b86a43c 100644 --- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php +++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php @@ -55,14 +55,6 @@ interface CacheBackendInterface { const CACHE_PERMANENT = 0; /** - * Constructs a new cache backend. - * - * @param $bin - * The cache bin for which the object is created. - */ - function __construct($bin); - - /** * Returns data from the persistent cache. * * Data may be stored as either plain text or as serialized data. cache_get() diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php index d4de8bf..664cada 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Cache; -use Drupal\Core\Database\Database; +use Drupal\Core\Database\Connection; use Exception; /** @@ -24,6 +24,12 @@ class DatabaseBackend implements CacheBackendInterface { protected $bin; /** + * A database connection object. + */ + protected $dbConnection; + + + /** * A static cache of all tags checked during the request. */ protected static $tagCache = array(); @@ -31,13 +37,18 @@ class DatabaseBackend implements CacheBackendInterface { /** * Implements Drupal\Core\Cache\CacheBackendInterface::__construct(). */ - function __construct($bin) { + function __construct(Connection $connection) { + $this->dbConnection = $connection; + } + + function bin($bin) { // All cache tables should be prefixed with 'cache_', except for the // default 'cache' bin. if ($bin != 'cache') { $bin = 'cache_' . $bin; } $this->bin = $bin; + return $this; } /** @@ -61,7 +72,7 @@ class DatabaseBackend implements CacheBackendInterface { // is used here only due to the performance overhead we would incur // otherwise. When serving an uncached page, the overhead of using // ::select() is a much smaller proportion of the request. - $result = Database::getConnection()->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . Database::getConnection()->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids)); + $result = $this->dbConnection->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . $this->dbConnection->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids)); $cache = array(); foreach ($result as $item) { $item = $this->prepareItem($item); @@ -136,7 +147,7 @@ class DatabaseBackend implements CacheBackendInterface { } try { - Database::getConnection()->merge($this->bin) + $this->dbConnection->merge($this->bin) ->key(array('cid' => $cid)) ->fields($fields) ->execute(); @@ -150,7 +161,7 @@ class DatabaseBackend implements CacheBackendInterface { * Implements Drupal\Core\Cache\CacheBackendInterface::delete(). */ function delete($cid) { - Database::getConnection()->delete($this->bin) + $this->dbConnection->delete($this->bin) ->condition('cid', $cid) ->execute(); } @@ -161,7 +172,7 @@ class DatabaseBackend implements CacheBackendInterface { function deleteMultiple(array $cids) { // Delete in chunks when a large array is passed. do { - Database::getConnection()->delete($this->bin) + $this->dbConnection->delete($this->bin) ->condition('cid', array_splice($cids, 0, 1000), 'IN') ->execute(); } @@ -172,8 +183,8 @@ class DatabaseBackend implements CacheBackendInterface { * Implements Drupal\Core\Cache\CacheBackendInterface::deletePrefix(). */ function deletePrefix($prefix) { - Database::getConnection()->delete($this->bin) - ->condition('cid', Database::getConnection()->escapeLike($prefix) . '%', 'LIKE') + $this->dbConnection->delete($this->bin) + ->condition('cid', $this->dbConnection->escapeLike($prefix) . '%', 'LIKE') ->execute(); } @@ -181,14 +192,14 @@ class DatabaseBackend implements CacheBackendInterface { * Implements Drupal\Core\Cache\CacheBackendInterface::flush(). */ function flush() { - Database::getConnection()->truncate($this->bin)->execute(); + $this->dbConnection->truncate($this->bin)->execute(); } /** * Implements Drupal\Core\Cache\CacheBackendInterface::expire(). */ function expire() { - Database::getConnection()->delete($this->bin) + $this->dbConnection->delete($this->bin) ->condition('expire', CacheBackendInterface::CACHE_PERMANENT, '<>') ->condition('expire', REQUEST_TIME, '<') ->execute(); @@ -251,7 +262,7 @@ class DatabaseBackend implements CacheBackendInterface { public function invalidateTags(array $tags) { foreach ($this->flattenTags($tags) as $tag) { unset(self::$tagCache[$tag]); - Database::getConnection()->merge('cache_tags') + $this->dbConnection->merge('cache_tags') ->key(array('tag' => $tag)) ->fields(array('invalidations' => 1)) ->expression('invalidations', 'invalidations + 1') @@ -282,7 +293,7 @@ class DatabaseBackend implements CacheBackendInterface { } if ($query_tags) { try { - if ($db_tags = Database::getConnection()->query('SELECT tag, invalidations FROM {cache_tags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllKeyed()) { + if ($db_tags = $this->dbConnection->query('SELECT tag, invalidations FROM {cache_tags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllKeyed()) { self::$tagCache = array_merge(self::$tagCache, $db_tags); $checksum += array_sum($db_tags); } @@ -299,7 +310,7 @@ class DatabaseBackend implements CacheBackendInterface { */ function isEmpty() { $this->garbageCollection(); - $query = Database::getConnection()->select($this->bin); + $query = $this->dbConnection->select($this->bin); $query->addExpression('1'); $result = $query->range(0, 1) ->execute() diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 2c5d180..cc0d32b 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -43,14 +43,6 @@ class CoreBundle extends Bundle $container->register('language_manager', 'Drupal\Core\Language\LanguageManager') ->addArgument(new Reference('request')) ->setScope('request'); - $container->register('database', 'Drupal\Core\Database\Connection') - ->setFactoryClass('Drupal\Core\Database\Database') - ->setFactoryMethod('getConnection') - ->addArgument('default'); - $container->register('database.slave', 'Drupal\Core\Database\Connection') - ->setFactoryClass('Drupal\Core\Database\Database') - ->setFactoryMethod('getConnection') - ->addArgument('slave'); // @todo Replace below lines with the commented out block below it when it's // performant to do so: http://drupal.org/node/1706064. diff --git a/core/lib/Drupal/Core/Database/Database.php b/core/lib/Drupal/Core/Database/Database.php index 6a425de..cd48edf 100644 --- a/core/lib/Drupal/Core/Database/Database.php +++ b/core/lib/Drupal/Core/Database/Database.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Database; +use LogicException; + /** * Primary front-controller for the database system. * @@ -144,15 +146,20 @@ abstract class Database { /** * Gets the connection object for the specified database key and target. * - * @param $target + * @param string $target * The database target name. * @param $key * The database connection key. Defaults to NULL which means the active key. + * @param array $database_info * * @return Drupal\Core\Database\Connection * The corresponding connection object. */ - final public static function getConnection($target = 'default', $key = NULL) { + final public static function getConnection($target = 'default', $key = NULL, $database_info = array()) { + if (empty(self::$databaseInfo)) { + self::parseConnectionInfo($database_info); + } + if (!isset($key)) { // By default, we want the active connection, set in setActiveConnection. $key = self::$activeKey; @@ -195,7 +202,7 @@ abstract class Database { */ final public static function setActiveConnection($key = 'default') { if (empty(self::$databaseInfo)) { - self::parseConnectionInfo(); + throw new LogicException('Database::setActiveConnection is called without specifying the database information first.'); } if (!empty(self::$databaseInfo[$key])) { @@ -208,10 +215,7 @@ abstract class Database { /** * Process the configuration file for database information. */ - final public static function parseConnectionInfo() { - global $databases; - - $database_info = is_array($databases) ? $databases : array(); + final public static function parseConnectionInfo($database_info) { foreach ($database_info as $index => $info) { foreach ($database_info[$index] as $target => $value) { // If there is no "driver" property, then we assume it's an array of @@ -287,7 +291,7 @@ abstract class Database { */ final public static function getConnectionInfo($key = 'default') { if (empty(self::$databaseInfo)) { - self::parseConnectionInfo(); + throw new LogicException('Database::getConnectionInfo called without specifying the database information first.'); } if (!empty(self::$databaseInfo[$key])) { @@ -307,7 +311,7 @@ abstract class Database { */ final public static function renameConnection($old_key, $new_key) { if (empty(self::$databaseInfo)) { - self::parseConnectionInfo(); + throw new LogicException('Database::renameConnection called without specifying the database information first.'); } if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) { @@ -359,9 +363,9 @@ abstract class Database { * @throws Drupal\Core\Database\ConnectionNotDefinedException * @throws Drupal\Core\Database\DriverNotSpecifiedException */ - final protected static function openConnection($key, $target) { + final protected static function openConnection($key, $target, $database_info = array()) { if (empty(self::$databaseInfo)) { - self::parseConnectionInfo(); + self::parseConnectionInfo($database_info); } // If the requested database does not exist then it is an unrecoverable diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index 9654f9c..992e762 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -780,6 +780,7 @@ abstract class TestBase { // Reset all static variables. drupal_static_reset(); + cache(NULL, TRUE); // Restore has_run state. $has_run = &drupal_static('module_load_all'); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 210b058..efcadda 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -602,6 +602,10 @@ abstract class WebTestBase extends TestBase { // Reset all statics and variables to perform tests in a clean environment. $conf = array(); drupal_static_reset(); + // drupal_container() does not use drupal_static(). + drupal_container(NULL, TRUE); + // Neither does cache(). + cache(NULL, TRUE); // Change the database prefix. // All static variables need to be reset before the database prefix is