Commit de33f74b authored by Dries's avatar Dries

- Patch #688704 by Crell, boombatower, noahb: give DB its own autoload function.

parent b647348f
......@@ -1947,6 +1947,10 @@ function _drupal_bootstrap_database() {
Database::setLoggingCallback('watchdog', WATCHDOG_NOTICE, WATCHDOG_ERROR);
// Register autoload functions so that we can access classes and interfaces.
// The database autoload routine comes first so that we can load the database
// system without hitting the database. That is especially important during
// the install or upgrade process.
spl_autoload_register('db_autoload');
spl_autoload_register('drupal_autoload_class');
spl_autoload_register('drupal_autoload_interface');
}
......@@ -2381,7 +2385,6 @@ function drupal_autoload_class($class) {
*/
function _registry_check_code($type, $name = NULL) {
static $lookup_cache, $cache_update_needed;
if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name)) {
return TRUE;
}
......
......@@ -41,8 +41,7 @@ function clear($cid = NULL, $wildcard = FALSE) {
// subtle bugs, some of which would not be fixed unless the site
// administrator cleared the cache manually.
try {
if (function_exists('drupal_install_initialize_database')) {
drupal_install_initialize_database();
if (class_exists('Database')) {
parent::clear($cid, $wildcard);
}
}
......
......@@ -761,7 +761,9 @@ public function truncate($table, array $options = array()) {
public function schema() {
if (empty($this->schema)) {
$class = $this->getDriverClass('DatabaseSchema');
$this->schema = new $class($this);
if (class_exists($class)) {
$this->schema = new $class($this);
}
}
return $this->schema;
}
......@@ -2109,6 +2111,73 @@ public function valid() {
}
}
/**
* Autoload callback for the database system.
*/
function db_autoload($class) {
static $base_path = '';
static $checked = array();
static $files = array(
'query.inc' => array(
'QueryPlaceholderInterface',
'QueryConditionInterface', 'DatabaseCondition',
'Query', 'DeleteQuery', 'InsertQuery', 'UpdateQuery', 'MergeQuery', 'TruncateQuery',
'QueryAlterableInterface',
),
'select.inc' => array('QueryAlterableInterface', 'SelectQueryInterface', 'SelectQuery', 'SelectQueryExtender'),
'database.inc' => array('DatabaseConnection'),
'log.inc' => array('DatabaseLog'),
'prefetch.inc' => array('DatabaseStatementPrefetch'),
'schema.inc' => array('DatabaseSchema'),
);
// If a class doesn't exist, it may get checked a second time
// by class_exists(). If so, just bail out now.
if (isset($checked[$class])) {
return;
}
$checked[$class] = TRUE;
if (empty($base_path)) {
$base_path = dirname(realpath(__FILE__));
}
// If there is an underscore in the class name, we know it's a
// driver-specific file so check for those. If not, it's a generic.
// Note that we use require_once here instead of require because of a
// quirk in class_exists(). By default, class_exists() will try to
// autoload a class if it's not found. However, we cannot tell
// at this point whether or not the class is going to exist, only
// the file that it would be in if it does exist. That means we may
// try to include a file that was already included by another
// autoload call, which would break. Using require_once() neatly
// avoids that issue.
if (strpos($class, '_') !== FALSE) {
list($base, $driver) = explode('_', $class);
// Drivers have an extra file, and may put their SelectQuery implementation
// in the main query file since it's so small.
$driver_files = $files;
$driver_files['query.inc'][] = 'SelectQuery';
$driver_files['install.inc'] = array('DatabaseTasks');
foreach ($driver_files as $file => $classes) {
if (in_array($base, $classes)) {
require_once "{$base_path}/{$driver}/{$file}";
return;
}
}
}
else {
foreach ($files as $file => $classes) {
if (in_array($class, $classes)) {
require_once $base_path . '/' . $file;
return;
}
}
}
}
/**
* The following utility functions are simply convenience wrappers.
......
......@@ -278,6 +278,7 @@ function install_begin_request(&$install_state) {
// Initialize the database system. Note that the connection
// won't be initialized until it is actually requested.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
spl_autoload_register('db_autoload');
// Verify the last completed task in the database, if there is one.
$task = install_verify_completed_task();
......@@ -350,7 +351,6 @@ function install_run_tasks(&$install_state) {
$install_state['tasks_performed'][] = $task_name;
$install_state['installation_finished'] = empty($tasks_to_perform);
if ($install_state['database_tables_exist'] && ($task['run'] == INSTALL_TASK_RUN_IF_NOT_COMPLETED || $install_state['installation_finished'])) {
drupal_install_initialize_database();
variable_set('install_task', $install_state['installation_finished'] ? 'done' : $task_name);
}
}
......@@ -1325,7 +1325,6 @@ function install_load_profile(&$install_state) {
function install_bootstrap_full(&$install_state) {
// Bootstrap newly installed Drupal, while preserving existing messages.
$messages = isset($_SESSION['messages']) ? $_SESSION['messages'] : '';
drupal_install_initialize_database();
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$_SESSION['messages'] = $messages;
......
......@@ -219,20 +219,14 @@ function drupal_detect_baseurl($file = 'install.php') {
function drupal_detect_database_types() {
$databases = array();
// Initialize the database system if it has not been
// initialized yet. We do not initialize it earlier to make
// requirements check during the installation.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
// We define a driver as a directory in /includes/database that in turn
// contains a database.inc file. That allows us to drop in additional drivers
// without modifying the installer.
// Because we have no registry yet, we need to also include the install.inc
// file for the driver explicitly.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
spl_autoload_register('db_autoload');
foreach (file_scan_directory(DRUPAL_ROOT . '/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
include_once "{$file->uri}/install.inc";
include_once "{$file->uri}/database.inc";
$drivers[$file->filename] = $file->uri;
}
......@@ -546,28 +540,6 @@ function drupal_verify_profile($install_state) {
return $requirements;
}
/**
* Manually include all files for the active database.
*
* Because we have no registry yet, we need to manually include the
* necessary database include files.
*/
function drupal_install_initialize_database() {
static $included = FALSE;
if (!$included) {
$connection_info = Database::getConnectionInfo();
$driver = $connection_info['default']['driver'];
require_once DRUPAL_ROOT . '/includes/database/query.inc';
require_once DRUPAL_ROOT . '/includes/database/select.inc';
require_once DRUPAL_ROOT . '/includes/database/schema.inc';
foreach (glob(DRUPAL_ROOT . '/includes/database/' . $driver . '/*.inc') as $include_file) {
require_once $include_file;
}
$included = TRUE;
}
}
/**
* Callback to install the system module.
*
......@@ -577,7 +549,6 @@ function drupal_install_initialize_database() {
function drupal_install_system() {
$system_path = dirname(drupal_get_filename('module', 'system', NULL));
require_once DRUPAL_ROOT . '/' . $system_path . '/system.install';
drupal_install_initialize_database();
module_invoke('system', 'install');
$system_versions = drupal_get_schema_versions('system');
......
......@@ -39,6 +39,7 @@ function _drupal_maintenance_theme() {
// Because we are operating in a crippled environment, we need to
// bootstrap just enough to allow hook invocations to work.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
spl_autoload_register('db_autoload');
$module_list['system']['filename'] = 'modules/system/system.module';
module_list(TRUE, FALSE, FALSE, $module_list);
drupal_load('module', 'system');
......
......@@ -102,9 +102,6 @@ function update_prepare_d7_bootstrap() {
// Allow the database system to work even if the registry has not been
// created yet.
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
drupal_install_initialize_database();
spl_autoload_unregister('drupal_autoload_class');
spl_autoload_unregister('drupal_autoload_interface');
// The new cache_bootstrap bin is required to bootstrap to
// DRUPAL_BOOTSTRAP_SESSION, so create it here rather than in
......
......@@ -566,6 +566,8 @@ protected function setUp() {
$this->originalPrefix = $db_prefix;
$this->originalFileDirectory = file_directory_path();
spl_autoload_register('db_autoload');
// Reset all statics so that test is performed with a clean environment.
drupal_static_reset();
......
......@@ -185,7 +185,9 @@ function simpletest_test_form_submit($form, &$form_state) {
// Get list of tests.
$tests_list = array();
foreach ($form_state['values'] as $class_name => $value) {
if (class_exists($class_name) && $value === 1) {
// Since class_exists() will likely trigger an autoload lookup,
// we do the fast check first.
if ($value === 1 && class_exists($class_name)) {
$tests_list[] = $class_name;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment