diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 77458a1..b58ec36 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -885,59 +885,38 @@ function drupal_get_filename($type, $name, $filename = NULL) { elseif (isset($files[$type][$name])) { // nothing } - // Verify that we have an active database connection, before querying - // the database. This is required because this function is called both - // before we have a database connection (i.e. during installation) and - // when a database connection fails. else { - try { - if (function_exists('db_query')) { - $file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField(); - if ($file && file_exists(DRUPAL_ROOT . '/' . $file)) { - $files[$type][$name] = $file; - } - } + // We have a consistent directory naming: modules, themes... + $dir = $type . 's'; + if ($type == 'theme_engine') { + $dir = 'themes/engines'; + $extension = 'engine'; + } + elseif ($type == 'theme') { + $extension = 'info'; + } + // Profiles are converted into modules in system_rebuild_module_data(). + // @todo Remove false-exposure of profiles as modules. + elseif ($original_type == 'profile') { + $dir = 'profiles'; + $extension = 'profile'; + } + else { + $extension = $type; } - catch (Exception $e) { - // The database table may not exist because Drupal is not yet installed, - // or the database might be down. We have a fallback for this case so we - // hide the error completely. - } - // Fallback to searching the filesystem if the database could not find the - // file or the file returned by the database is not found. - if (!isset($files[$type][$name])) { - // We have a consistent directory naming: modules, themes... - $dir = $type . 's'; - if ($type == 'theme_engine') { - $dir = 'themes/engines'; - $extension = 'engine'; - } - elseif ($type == 'theme') { - $extension = 'info'; - } - // Profiles are converted into modules in system_rebuild_module_data(). - // @todo Remove false-exposure of profiles as modules. - elseif ($original_type == 'profile') { - $dir = 'profiles'; - $extension = 'profile'; - } - else { - $extension = $type; - } - if (!isset($dirs[$dir][$extension])) { - $dirs[$dir][$extension] = TRUE; - if (!function_exists('drupal_system_listing')) { - require_once DRUPAL_ROOT . '/core/includes/common.inc'; - } - // Scan the appropriate directories for all files with the requested - // extension, not just the file we are currently looking for. This - // prevents unnecessary scans from being repeated when this function is - // called more than once in the same page request. - $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0); - foreach ($matches as $matched_name => $file) { - $files[$type][$matched_name] = $file->uri; - } + if (!isset($dirs[$dir][$extension])) { + $dirs[$dir][$extension] = TRUE; + if (!function_exists('drupal_system_listing')) { + require_once DRUPAL_ROOT . '/core/includes/common.inc'; + } + // Scan the appropriate directories for all files with the requested + // extension, not just the file we are currently looking for. This + // prevents unnecessary scans from being repeated when this function is + // called more than once in the same page request. + $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0); + foreach ($matches as $matched_name => $file) { + $files[$type][$matched_name] = $file->uri; } } } @@ -2102,14 +2081,15 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { ); // Not drupal_static(), because the only legitimate API to control this is to // call drupal_bootstrap() with a new phase parameter. - static $final_phase; + static $final_phase = -1; // Not drupal_static(), because it's impossible to roll back to an earlier // bootstrap state. static $stored_phase = -1; - // When not recursing, store the phase name so it's not forgotten while - // recursing. - if ($new_phase) { + // When not recursing, store the phase name so it's not forgotten during + // recursion. Additionally, ensure that $final_phase is never rolled back to an + // earlier bootstrap state. + if ($new_phase && $phase > $final_phase) { $final_phase = $phase; } if (isset($phase)) { @@ -2390,7 +2370,7 @@ function _drupal_bootstrap_page_header() { * @see drupal_bootstrap() */ function drupal_get_bootstrap_phase() { - return drupal_bootstrap(); + return drupal_bootstrap(NULL, FALSE); } /** @@ -2462,8 +2442,7 @@ function drupal_container(Container $new_container = NULL, $rebuild = FALSE) { ->register('config.storage.staging', 'Drupal\Core\Config\FileStorage') ->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY)); $container - ->register('state.storage', 'Drupal\Core\KeyValueStore\DatabaseStorage') - ->addArgument('state'); + ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory'); } return $container; } @@ -2480,7 +2459,7 @@ function drupal_container(Container $new_container = NULL, $rebuild = FALSE) { * @return Drupal\Core\KeyValueStore\KeyValueStoreInterface */ function state() { - return drupal_container()->get('state.storage'); + return drupal_container()->get('keyvalue')->get('state.storage'); } /** @@ -2499,16 +2478,21 @@ function typed_data() { /** * Returns the test prefix if this is an internal request from SimpleTest. * + * @param string $new_prefix + * Internal use only. A new prefix to be stored. + * * @return * Either the simpletest prefix (the string "simpletest" followed by any * number of digits) or FALSE if the user agent does not contain a valid * HMAC and timestamp. */ -function drupal_valid_test_ua() { +function drupal_valid_test_ua($new_prefix = NULL) { global $drupal_hash_salt; - // No reason to reset this. static $test_prefix; + if (isset($new_prefix)) { + $test_prefix = $new_prefix; + } if (isset($test_prefix)) { return $test_prefix; } diff --git a/core/includes/common.inc b/core/includes/common.inc index 6879def..6eba01f 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -6804,18 +6804,12 @@ function drupal_flush_all_caches() { // None currently; kept if any static caches need to be reset in the future. // Rebuild module and theme data. - system_rebuild_module_data(); - system_rebuild_theme_data(); + system_list_reset(); // Ensure that all modules that are currently supposed to be enabled are // actually loaded. module_load_all(); - // Update the list of bootstrap modules. - // Allows developers to get new hook_boot() implementations registered without - // having to write a hook_update_N() function. - _system_update_bootstrap_status(); - // Rebuild the schema and cache a fully-built schema based on new module data. // This is necessary for any invocation of index.php, because setting cache // table entries requires schema information and that occurs during bootstrap diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 17e2a66..243f6d8 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1655,15 +1655,12 @@ function install_import_translations_remaining(&$install_state) { * A message informing the user that the installation is complete. */ function install_finished(&$install_state) { + $profile = drupal_get_profile(); // Remember the profile which was used. - variable_set('install_profile', drupal_get_profile()); + variable_set('install_profile', $profile); // Install profiles are always loaded last. - db_update('system') - ->fields(array('weight' => 1000)) - ->condition('type', 'module') - ->condition('name', drupal_get_profile()) - ->execute(); + module_set_weight($profile, 1000); // Flush all caches to ensure that any full bootstraps during the installer // do not leave stale cached data, and that any content types or other items diff --git a/core/includes/install.inc b/core/includes/install.inc index efba3c1..1ddeda1 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -6,19 +6,10 @@ */ use Drupal\Core\Database\Database; +use Drupal\Core\KeyValueStore\KeyValueFactory; use Drupal\locale\Gettext; /** - * Indicates that a module has not been installed yet. - */ -const SCHEMA_UNINSTALLED = -1; - -/** - * Indicates that a module has been installed. - */ -const SCHEMA_INSTALLED = 0; - -/** * Requirement severity -- Informational message only. */ const REQUIREMENT_INFO = -1; @@ -418,20 +409,16 @@ function drupal_install_system() { $system_path = drupal_get_path('module', 'system'); require_once DRUPAL_ROOT . '/' . $system_path . '/system.install'; - $system_versions = drupal_get_schema_versions('system'); - $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; - db_insert('system') - ->fields(array('filename', 'name', 'type', 'owner', 'status', 'schema_version', 'bootstrap')) - ->values(array( - 'filename' => $system_path . '/system.module', - 'name' => 'system', - 'type' => 'module', - 'owner' => '', - 'status' => 1, - 'schema_version' => $system_version, - 'bootstrap' => 0, - )) - ->execute(); + if ($system_versions = drupal_get_schema_versions('system')) { + drupal_container() + ->get('keyvalue') + ->get('system.module.schema') + ->set('system', max($system_versions)); + } + config('system.module') + ->set('system', 0) + ->call('module_config_sort') + ->save(); // Clear out module list and hook implementation statics before calling // system_rebuild_theme_data(). @@ -439,9 +426,6 @@ function drupal_install_system() { module_list_reset(); module_implements_reset(); - system_rebuild_module_data(); - system_rebuild_theme_data(); - config_install_default_config('module', 'system'); module_invoke('system', 'install'); diff --git a/core/includes/module.inc b/core/includes/module.inc index c202b8e..05bbed0 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -6,6 +6,7 @@ */ use Drupal\Component\Graph\Graph; +use Drupal\Core\KeyValueStore\KeyValueFactory; /** * Loads all the modules that have been enabled in the system table. @@ -14,24 +15,14 @@ use Drupal\Component\Graph\Graph; * Whether to load only the reduced set of modules loaded in "bootstrap mode" * for cached pages. See bootstrap.inc. Pass NULL to only check the current * status without loading of modules. - * @param bool $reset - * (optional) Internal use only. Whether to reset the internal statically - * cached flag of whether modules have been loaded. If TRUE, all modules are - * (re)loaded in the same call. Used by the testing framework to override and - * persist a limited module list for the duration of a unit test (in which no - * module system exists). * * @return bool * A Boolean indicating whether all modules have been loaded. This means all * modules; the load status of bootstrap modules cannot be checked. */ -function module_load_all($bootstrap = FALSE, $reset = FALSE) { +function module_load_all($bootstrap = FALSE) { static $has_run = FALSE; - if ($reset) { - $has_run = FALSE; - } - // Unless $boostrap is NULL, load the requested set of modules. if (isset($bootstrap) && !$has_run) { $type = $bootstrap ? 'bootstrap' : 'module_enabled'; @@ -144,22 +135,20 @@ function system_list($type) { return $lists['bootstrap']; } if ($cached = cache('bootstrap')->get('bootstrap_modules')) { - $bootstrap_list = $cached->data; + $lists['bootstrap'] = $cached->data; + // To avoid a separate database lookup for the filepath, prime the + // drupal_get_filename() static cache for bootstrap modules only. + // The rest is stored separately to keep the bootstrap module cache small. + foreach ($lists['bootstrap'] as $module => $filename) { + _system_list_warm('module', $module, $filename); + } } else { - $bootstrap_list = db_query("SELECT name, filename FROM {system} WHERE status = 1 AND bootstrap = 1 AND type = 'module' ORDER BY weight ASC, name ASC")->fetchAllAssoc('name'); - cache('bootstrap')->set('bootstrap_modules', $bootstrap_list); - } - // To avoid a separate database lookup for the filepath, prime the - // drupal_get_filename() static cache for bootstrap modules only. - // The rest is stored separately to keep the bootstrap module cache small. - foreach ($bootstrap_list as $module) { - drupal_classloader_register($module->name, dirname($module->filename)); - drupal_get_filename('module', $module->name, $module->filename); + $lists = _system_list_prepare(); } // We only return the module names here since module_list() doesn't need // the filename itself. - $lists['bootstrap'] = array_keys($bootstrap_list); + $lists['bootstrap'] = array_keys($lists['bootstrap']); } // Otherwise build the list for enabled modules and themes. elseif (!isset($lists['module_enabled'])) { @@ -167,68 +156,130 @@ function system_list($type) { $lists = $cached->data; } else { - $lists = array( - 'module_enabled' => array(), - 'theme' => array(), - 'filepaths' => array(), + $lists = _system_list_prepare(); + $lists['bootstrap'] = array_keys($lists['bootstrap']); + } + foreach ($lists['filepaths'] as $item) { + _system_list_warm($item['type'], $item['name'], $item['filepath']); + } + } + + return $lists[$type]; +} + +/** + * Prepares the system list data structure. + * + * @return + * An associative array of modules and themes, keyed by list type: bootstrap, + * module_enabled, theme, filepaths. + */ +function _system_list_prepare() { + // The module name (rather than the filename) is used as the fallback + // weighting in order to guarantee consistent behavior across different + // Drupal installations, which might have modules installed in different + // locations in the file system. The ordering here must also be + // consistent with the one used in module_implements(). + $enabled_themes = config('system.theme')->get(); + $enabled_modules = config('system.module')->get(); + _system_list_warm('module', 'system', 'core/modules/system.module', TRUE); + + $module_file_list = state()->get('system.module_file_list'); + $theme_data = state()->get('system.themes'); + // As themes do not need to be installed to be used there is an issue during + // installation. The state entry for system.themes does not exist and we need + // theme data in order for installation to work. This will be resolved by + // http://drupal.org/node/1067408. + if (empty($theme_data)) { + $theme_data = system_rebuild_theme_data(FALSE); + } + $lists = array( + 'bootstrap' => array(), + 'module_enabled' => array(), + 'theme' => array(), + 'filepaths' => array(), + ); + foreach ($theme_data as $key => $theme) { + $lists['theme'][$key] = $theme; + $status = isset($enabled_themes[$key]); + $lists['theme'][$key]->status = $status; + $lists['theme'][$key]->name = $key; + // Build a list of filenames so drupal_get_filename can use it. + if ($status) { + $lists['filepaths'][] = array( + 'type' => 'theme', + 'name' => $key, + 'filepath' => $theme->filename ); - // The module name (rather than the filename) is used as the fallback - // weighting in order to guarantee consistent behavior across different - // Drupal installations, which might have modules installed in different - // locations in the file system. The ordering here must also be - // consistent with the one used in module_implements(). - $result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC"); - foreach ($result as $record) { - // Build a list of all enabled modules. - if ($record->type == 'module') { - $lists['module_enabled'][$record->name] = $record->name; - } - // Build a list of themes. - if ($record->type == 'theme') { - $record->info = unserialize($record->info); - $lists['theme'][$record->name] = $record; - } - // Build a list of filenames so drupal_get_filename can use it. - if ($record->status) { - $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename); - } + } + } + foreach ($lists['theme'] as $key => $theme) { + if (!empty($theme->info['base theme'])) { + // Make a list of the theme's base themes. + require_once DRUPAL_ROOT . '/core/includes/theme.inc'; + $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key); + // Don't proceed if there was a problem with the root base theme. + if (!current($lists['theme'][$key]->base_themes)) { + continue; } - foreach ($lists['theme'] as $key => $theme) { - if (!empty($theme->info['base theme'])) { - // Make a list of the theme's base themes. - require_once DRUPAL_ROOT . '/core/includes/theme.inc'; - $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key); - // Don't proceed if there was a problem with the root base theme. - if (!current($lists['theme'][$key]->base_themes)) { - continue; - } - // Determine the root base theme. - $base_key = key($lists['theme'][$key]->base_themes); - // Add to the list of sub-themes for each of the theme's base themes. - foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) { - $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name']; - } - // Add the base theme's theme engine info. - $lists['theme'][$key]->info['engine'] = $lists['theme'][$base_key]->info['engine']; - } - else { - // A plain theme is its own base theme. - $base_key = $key; - } - // Set the theme engine prefix. - $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine']; + // Determine the root base theme. + $base_key = key($lists['theme'][$key]->base_themes); + // Add to the list of sub-themes for each of the theme's base themes. + foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) { + $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name']; } - cache('bootstrap')->set('system_list', $lists); + // Add the base theme's theme engine info. + $lists['theme'][$key]->info['engine'] = $lists['theme'][$base_key]->info['engine']; } - // To avoid a separate database lookup for the filepath, prime the - // drupal_get_filename() static cache with all enabled modules and themes. - foreach ($lists['filepaths'] as $item) { - drupal_get_filename($item['type'], $item['name'], $item['filepath']); - drupal_classloader_register($item['name'], dirname($item['filepath'])); + else { + // A plain theme is its own base theme. + $base_key = $key; } + // Set the theme engine prefix. + $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine']; } - return $lists[$type]; + foreach ($enabled_modules as $name => $weight) { + // Build a list of all enabled modules. + $lists['module_enabled'][$name] = $name; + $filename = $module_file_list[$name]; + // Build a list of filenames so drupal_get_filename can use it. + $lists['filepaths'][] = array( + 'type' => 'module', + 'name' => $name, + 'filepath' => $filename, + ); + _system_list_warm('module', $name, $filename, TRUE); + foreach (bootstrap_hooks() as $hook) { + if (function_exists($name .'_' . $hook)) { + $lists['bootstrap'][$name] = $filename; + } + } + } + cache('bootstrap')->set('system_list', $lists); + cache('bootstrap')->set('bootstrap_modules', $lists['bootstrap']); + + return $lists; +} + +/** + * Prepares a module for loading and optionally calls drupal_load(). + * + * @param string $type + * The type of the extension (i.e. theme, theme_engine, module, profile). + * @param string $name + * The name of the extension. + * @param string $filename + * The filename of the extension. + * @param bool $load + * (optional) Call drupal_load() for the extension. Defaults to FALSE. + */ +function _system_list_warm($type, $name, $filename, $load = FALSE) { + drupal_classloader_register($name, dirname($filename)); + drupal_get_filename($type, $name, $filename); + if ($load) { + drupal_load($type, $name); + } } /** @@ -394,27 +445,28 @@ function module_load_all_includes($type, $name = NULL) { * @see hook_modules_enabled() */ function module_enable($module_list, $enable_dependencies = TRUE) { + // Get all module data so we can find dependencies, sort and copy to the + // installed modules config. + $all_modules = system_rebuild_module_data(); if ($enable_dependencies) { - // Get all module data so we can find dependencies and sort. - $module_data = system_rebuild_module_data(); // Create an associative array with weights as values. $module_list = array_flip(array_values($module_list)); while (list($module) = each($module_list)) { - if (!isset($module_data[$module])) { + if (!isset($all_modules[$module])) { // This module is not found in the filesystem, abort. return FALSE; } - if ($module_data[$module]->status) { + if ($all_modules[$module]->status) { // Skip already enabled modules. unset($module_list[$module]); continue; } - $module_list[$module] = $module_data[$module]->sort; + $module_list[$module] = $all_modules[$module]->sort; // Add dependencies to the list, with a placeholder weight. // The new modules will be processed as the while loop continues. - foreach (array_keys($module_data[$module]->requires) as $dependency) { + foreach (array_keys($all_modules[$module]->requires) as $dependency) { if (!isset($module_list[$dependency])) { $module_list[$dependency] = 0; } @@ -436,30 +488,37 @@ function module_enable($module_list, $enable_dependencies = TRUE) { $modules_installed = array(); $modules_enabled = array(); + $schema_store = drupal_container()->get('keyvalue')->get('system.module.schema'); foreach ($module_list as $module) { + $config = config('system.module'); + $disabled_config = config('system.module.disabled'); // Only process modules that are not already enabled. - $existing = db_query("SELECT status FROM {system} WHERE type = :type AND name = :name", array( - ':type' => 'module', - ':name' => $module)) - ->fetchObject(); - if ($existing->status == 0) { + $enabled = TRUE; + $weight = 0; + if (!$schema_store->get($module)) { + $enabled = FALSE; + } + elseif (!$config->get($module)) { + $enabled = FALSE; + $weight = $disabled_config->get($module); + } + if (!$enabled) { + $config + ->set($module, $weight) + ->call('module_config_sort') + ->save(); + if ($weight) { + $disabled_config + ->clear($module) + ->save(); + } // Load the module's code. drupal_load('module', $module); module_load_install($module); - // Update the database and module list to reflect the new module. This - // needs to be done first so that the module's hook implementations, - // hook_schema() in particular, can be called while it is being - // installed. - db_update('system') - ->fields(array('status' => 1)) - ->condition('type', 'module') - ->condition('name', $module) - ->execute(); // Refresh the module list to include it. system_list_reset(); module_implements_reset(); - _system_update_bootstrap_status(); // Refresh the schema to include it. drupal_get_schema(NULL, TRUE); // Update the theme registry to include it. @@ -567,13 +626,19 @@ function module_disable($module_list, $disable_dependents = TRUE) { foreach ($module_list as $module) { if (module_exists($module)) { + $config = config('system.module'); + $disabled_config = config('system.module.disabled'); module_load_install($module); module_invoke($module, 'disable'); - db_update('system') - ->fields(array('status' => 0)) - ->condition('type', 'module') - ->condition('name', $module) - ->execute(); + if ($weight = $config->get($module)) { + $disabled_config + ->set($module, $weight) + ->save(); + } + $config + ->clear($module) + ->call('module_config_sort') + ->save(); $invoke_modules[] = $module; watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO); } @@ -587,7 +652,6 @@ function module_disable($module_list, $disable_dependents = TRUE) { // Invoke hook_modules_disabled before disabling modules, // so we can still call module hooks to get information. module_invoke_all('modules_disabled', $invoke_modules); - _system_update_bootstrap_status(); // Update the theme registry to remove the newly-disabled module. drupal_theme_rebuild(); } @@ -642,6 +706,8 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) } $storage = drupal_container()->get('config.storage'); + $schema_store = drupal_container()->get('keyvalue')->get('system.module.schema'); + $disabled_config = config('system.module.disabled'); foreach ($module_list as $module) { // Uninstall the module. module_load_install($module); @@ -655,8 +721,11 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) } watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO); - drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED); + $schema_store->delete($module); + $disabled_config->clear($module); } + $disabled_config->save(); + drupal_get_installed_schema_version(NULL, TRUE); if (!empty($module_list)) { // Call hook_module_uninstall to let other modules act @@ -1124,3 +1193,66 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { $function($data, $context1, $context2); } } + +/** + * Sets weight of a particular module. + * + * @param string $module + * The name of the module (without the .module extension). + * @param int $weight + * An integer representing the weight of the module. + */ +function module_set_weight($module, $weight) { + $config = config('system.module'); + + // If the module is enabled it will be in the system.module config file. + if ($config->get($module) !== NULL) { + $config + ->set($module, $weight) + ->call('module_config_sort') + ->save(); + } + // Before writing to the system.module.disabled file ensure that the module + // has been previously enabled. + else if (drupal_container()->get('keyvalue')->get('system.module.schema')->get($module) !== FALSE) { + $config_disabled = config('system.module.disabled'); + // Only save non-zero weights to the system.module.disabled config file. + if ($weight) { + $config_disabled + ->set($module, $weight) + ->save(); + } + else { + $config_disabled + ->clear($module) + ->save(); + } + } +} + +/** + * Sort module config. + * + * The list of enabled modules is expected to be weight and name order and it + * is faster to do this sort on write than on read. + * + * @param array $data + * An array of module configuration data. + * + * @return array + * An array of module configuration data sorted by weight. + */ +function module_config_sort($data) { + $sort = array(); + foreach ($data as $name => $weight) { + // We can't use the sign directly because + (ASCII 43) is before + // - (ASCII 45). So negative nubmers get a 0, non-negative numbers + // a 1 prefix. + $prefix = (int) ($weight >= 0); + // PHP_INT_MAX is at most 19 characters so make every number equally + // 19 digits long. + $sort[] = $prefix . sprintf('%019d', abs($weight)) . $name; + } + array_multisort($sort, SORT_STRING, $data); + return $data; +} diff --git a/core/includes/schema.inc b/core/includes/schema.inc index 7b0c690..4a73381 100644 --- a/core/includes/schema.inc +++ b/core/includes/schema.inc @@ -6,6 +6,7 @@ */ use Drupal\Core\Database\Database; +use Drupal\Core\KeyValueStore\KeyValueFactory; use Drupal\Core\Utility\SchemaCache; /** @@ -172,10 +173,8 @@ function drupal_get_installed_schema_version($module, $reset = FALSE, $array = F } if (!$versions) { - $versions = array(); - $result = db_query("SELECT name, schema_version FROM {system} WHERE type = :type", array(':type' => 'module')); - foreach ($result as $row) { - $versions[$row->name] = $row->schema_version; + if (!$versions = drupal_container()->get('keyvalue')->get('system.module.schema')->getAll()) { + $versions= array(); } } @@ -196,11 +195,7 @@ function drupal_get_installed_schema_version($module, $reset = FALSE, $array = F * The new schema version. */ function drupal_set_installed_schema_version($module, $version) { - db_update('system') - ->fields(array('schema_version' => $version)) - ->condition('name', $module) - ->execute(); - + drupal_container()->get('keyvalue')->get('system.module.schema')->set($module, $version); // Reset the static cache of module schema versions. drupal_get_installed_schema_version(NULL, TRUE); } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index cb7a84d..0a5df4f 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1408,19 +1408,19 @@ function theme_render_template($template_file, $variables) { */ function theme_enable($theme_list) { drupal_clear_css_cache(); - + $config = config('system.theme'); foreach ($theme_list as $key) { - db_update('system') - ->fields(array('status' => 1)) - ->condition('type', 'theme') - ->condition('name', $key) - ->execute(); - + // The value is not used, it needs to be consistent with + // config('system.module') which uses the value for weight so set all of + // them to the same value. 1 looks like 'enabled' so let's use that. + $config->set($key, 1); // Install default configuration of the theme. config_install_default_config('theme', $key); } + $config->save(); - list_themes(TRUE); + system_list_reset(); + system_rebuild_theme_data(TRUE); menu_router_rebuild(); drupal_theme_rebuild(); @@ -1445,13 +1445,11 @@ function theme_disable($theme_list) { drupal_clear_css_cache(); + $config = config('system.theme'); foreach ($theme_list as $key) { - db_update('system') - ->fields(array('status' => 0)) - ->condition('type', 'theme') - ->condition('name', $key) - ->execute(); + $config->clear($key); } + $config->save(); list_themes(TRUE); menu_router_rebuild(); diff --git a/core/includes/update.inc b/core/includes/update.inc index d8f94b4..c661b51 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -26,18 +26,25 @@ const REQUIRED_D7_SCHEMA_VERSION = '7069'; * Disable any items in the {system} table that are not core compatible. */ function update_fix_compatibility() { - $incompatible = array(); - $result = db_query("SELECT name, type, status FROM {system} WHERE status = 1 AND type IN ('module','theme')"); - foreach ($result as $row) { - if (update_check_incompatibility($row->name, $row->type)) { - $incompatible[] = $row->name; + foreach (array('module', 'theme') as $type) { + $config = config("system.$type"); + $save = FALSE; + foreach ($config->get() as $name => $weight) { + if (update_check_incompatibility($name, $type)) { + $config->clear($name); + $save = TRUE; + } + } + if ($save) { + if ($type == 'module') { + $config + ->call('module_config_sort') + ->save(); + } + else { + $config->save(); + } } - } - if (!empty($incompatible)) { - db_update('system') - ->fields(array('status' => 0)) - ->condition('name', $incompatible, 'IN') - ->execute(); } } @@ -116,7 +123,12 @@ function update_prepare_d8_bootstrap() { // running an up-to-date version of Drupal 7 before proceeding. Note this has // to happen AFTER the database bootstraps because of // drupal_get_installed_schema_version(). - $system_schema = drupal_get_installed_schema_version('system'); + try { + $system_schema = drupal_get_installed_schema_version('system'); + } + catch (\Exception $e) { + $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(':system' => 'system'))->fetchField(); + } if ($system_schema < 8000) { $has_required_schema = $system_schema >= REQUIRED_D7_SCHEMA_VERSION; $requirements = array( @@ -163,17 +175,53 @@ function update_prepare_d8_bootstrap() { // Bootstrap variables so we can update theme while preparing the update // process. drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES); - // Update the dynamic include paths that might be used before running the - // proper update functions. - update_prepare_stored_includes(); - // Update the environment for the language bootstrap if needed. - update_prepare_d8_language(); // Ensure the configuration directories exist and are writable, or create // them. If the directories have not been specified in settings.php and // created manually already, and either directory cannot be created by the // web server, an exception will be thrown, halting the update. drupal_install_config_directories(); + $configs = array( + 'module' => config('system.module'), + 'disabled_module' => config('system.module.disabled'), + 'theme' => config('system.theme'), + ); + $schema_store = drupal_container()->get('keyvalue')->get('system.module.schema'); + $result = db_query('SELECT name, status, weight, schema_version, type FROM {system} WHERE type = :theme OR (type = :module AND schema_version <> :schema_uninstalled)', array( + ':theme' => 'theme', + ':module' => 'module', + ':schema_uninstalled' => SCHEMA_UNINSTALLED, + )); + + // We include system.module because update.php does not always include + // it. + require_once DRUPAL_ROOT . '/core/modules/system/system.module'; + $module_data = system_rebuild_module_data(); + + // Loop through each extension from the system table. + foreach ($result as $file) { + if ($file->status && isset($module_data[$file->name])) { + $configs[$file->type]->set($file->name, $file->type == 'module' ? $file->weight : 1); + } + if ($file->type == 'module') { + $schema_store->set($file->name, $file->schema_version); + if (!$file->status && $file->weight) { + $configs['disabled_module']->set($file->name, $file->weight); + } + } + } + $configs['module']->call('module_config_sort'); + foreach ($configs as $config) { + $config->save(); + } + + // Update the dynamic include paths that might be used before running the + // proper update functions. + update_prepare_stored_includes(); + // Update the environment for the language bootstrap if needed. + update_prepare_d8_language(); + // Prime the classloader. + system_list('module_enabled'); // Change language column to langcode in url_alias. if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) { @@ -259,7 +307,6 @@ function update_prepare_d8_language() { // version of this function to ensure schema conflicts don't happen due to // our updated data. $modules = array('language'); - update_module_add_to_system($modules); update_module_enable($modules); // Rename language column to langcode and set it again as the primary key. @@ -331,41 +378,6 @@ function update_prepare_d8_language() { } /** - * Adds modules to the system table in a Drupal core update. - * - * @param $modules - * Array of module names. - */ -function update_module_add_to_system($modules = array()) { - // Insert module data, so we can enable the module. Calling a full module - // list rebuild so early is costly and complex, so we just have a stop-gap. - $info_defaults = array( - 'dependencies' => array(), - 'description' => '', - 'package' => 'Other', - 'version' => NULL, - 'php' => DRUPAL_MINIMUM_PHP, - 'files' => array(), - 'bootstrap' => 0, - ); - foreach ($modules as $module) { - $module_info = drupal_parse_info_file('core/modules/' . $module . '/' . $module . '.info'); - db_insert('system') - ->fields(array( - 'filename' => 'core/modules/' . $module . '/' . $module . '.module', - 'name' => $module, - 'type' => 'module', - 'status' => 0, - 'bootstrap' => 0, - 'schema_version' => -1, - 'weight' => 0, - 'info' => serialize($module_info + $info_defaults), - )) - ->execute(); - } -} - -/** * Perform Drupal 7.x to 8.x updates that are required for update.php * to function properly. * @@ -387,6 +399,7 @@ function update_fix_d8_requirements() { * Helper function to install a new module in Drupal 8 via hook_update_N(). */ function update_module_enable(array $modules) { + $store = drupal_container()->get('keyvalue')->get('system.module.schema'); foreach ($modules as $module) { // Check for initial schema and install it. The schema version of a newly // installed module is always 0. Using 8000 here would be inconsistent @@ -399,13 +412,13 @@ function update_module_enable(array $modules) { db_create_table($table, $spec); } } + // Enable the module with a weight of 0. + config('system.module') + ->set($module, 0) + ->save('module_config_sort'); // Change the schema version from SCHEMA_UNINSTALLED to 0, so any module // updates since the module's inception are executed in a core upgrade. - db_update('system') - ->condition('type', 'module') - ->condition('name', $module) - ->fields(array('schema_version' => 0, 'status' => 1)) - ->execute(); + $store->set($module, 0); // system_list_reset() is in module.inc but that would only be available // once the variable bootstrap is done. @@ -940,8 +953,7 @@ function update_retrieve_dependencies() { $return = array(); // Get a list of installed modules, arranged so that we invoke their hooks in // the same order that module_invoke_all() does. - $modules = db_query("SELECT name FROM {system} WHERE type = 'module' AND schema_version <> :schema ORDER BY weight ASC, name ASC", array(':schema' => SCHEMA_UNINSTALLED))->fetchCol(); - foreach ($modules as $module) { + foreach (config('system.module')->get() as $module => $data) { $function = $module . '_update_dependencies'; if (function_exists($function)) { $result = $function(); diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index 7c150e9..1f2796e 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -63,6 +63,7 @@ class Config { * @var Symfony\Component\EventDispatcher\EventDispatcher */ protected $eventDispatcher; + protected $sorted; /** * Constructs a configuration object. @@ -346,13 +347,35 @@ class Config { * The configuration object. */ public function save() { - $this->sortByKey($this->data); + // @TODO remove with http://drupal.org/node/1785560 + if (!$this->sorted) { + $this->sortByKey($this->data); + } $this->storage->write($this->name, $this->data); $this->isNew = FALSE; $this->notify('save'); return $this; } + /** + * Calls a PHP callable with the current data. + * + * This allows adding an arbitrary callback to a chain of config method + * calls. + * + * @param callable $callable + * A PHP callable. + * + * @return Drupal\Core\Config\Config + * The configuration object. + */ + public function call($callable) { + $this->data = $callable($this->data); + // @TODO remove with http://drupal.org/node/1785560 + $this->sorted = TRUE; + return $this; + } + /* * Renames the configuration object. * diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php new file mode 100644 index 0000000..897855e --- /dev/null +++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php @@ -0,0 +1,20 @@ +assertEqual($row->message, $expected_message, format_string('Expected message %expected, got %message.', array('%expected' => $expected_message, '%message' => $row->message))); diff --git a/core/modules/action/tests/action_loop_test/action_loop_test.install b/core/modules/action/tests/action_loop_test/action_loop_test.install index 50e3603..7085aed 100644 --- a/core/modules/action/tests/action_loop_test/action_loop_test.install +++ b/core/modules/action/tests/action_loop_test/action_loop_test.install @@ -4,8 +4,5 @@ * Implements hook_install(). */ function action_loop_test_install() { - db_update('system') - ->fields(array('weight' => 1)) - ->condition('name', 'action_loop_test') - ->execute(); + module_set_weight('action_loop_test', 1); } diff --git a/core/modules/block/block.install b/core/modules/block/block.install index 09ba522..5ad23aa 100644 --- a/core/modules/block/block.install +++ b/core/modules/block/block.install @@ -213,14 +213,10 @@ function block_schema() { * Implements hook_install(). */ function block_install() { - // Block should go first so that other modules can alter its output // during hook_page_alter(). Almost everything on the page is a block, // so before block module runs, there will not be much to alter. - db_update('system') - ->fields(array('weight' => -5)) - ->condition('name', 'block') - ->execute(); + module_set_weight('block', -5); } /** diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 0626c08..2978146 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -958,12 +958,10 @@ function block_cache_flush() { * Implements hook_rebuild(). */ function block_rebuild() { - // Rehash blocks for active themes. We don't use list_themes() here, - // because if MAINTENANCE_MODE is defined it skips reading the database, - // and we can't tell which themes are active. - $themes = db_query("SELECT name FROM {system} WHERE type = 'theme' AND status = 1"); - foreach ($themes as $theme) { - _block_rehash($theme->name); + foreach (list_themes() as $name => $data) { + if ($data->status) { + _block_rehash($name); + } } } diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 2274b93..fdedc1c 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -334,8 +334,17 @@ function field_cron() { * required if there are any active fields of that type. */ function field_system_info_alter(&$info, $file, $type) { - if ($type == 'module' && module_hook($file->name, 'field_info')) { - $fields = field_read_fields(array('module' => $file->name), array('include_deleted' => TRUE)); + // module_hook() relies on the very function this is called from: + // system_rebuild_module_data(). + $function = $file->name . '_field_info'; + if ($type == 'module' && function_exists($function)) { + try { + $fields = field_read_fields(array('module' => $file->name), array('include_deleted' => TRUE)); + } + catch (Exception $e) { + // The field_config table is not yet installed. Nothing to do. + return; + } if ($fields) { $info['required'] = TRUE; @@ -349,7 +358,8 @@ function field_system_info_alter(&$info, $file, $type) { } } if ($non_deleted) { - if (module_exists('field_ui')) { + // Calling module_exists() here leads to infinite recursion. + if (config('system.module')->get('field_ui') !== NULL) { $explanation = t('Field type(s) in use - see Field list', array('@fields-page' => url('admin/reports/fields'))); } else { diff --git a/core/modules/field/tests/modules/field_test/field_test.install b/core/modules/field/tests/modules/field_test/field_test.install index 5957561..5355e9b 100644 --- a/core/modules/field/tests/modules/field_test/field_test.install +++ b/core/modules/field/tests/modules/field_test/field_test.install @@ -10,10 +10,7 @@ */ function field_test_install() { // hook_entity_info_alter() needs to be executed as last. - db_update('system') - ->fields(array('weight' => 1)) - ->condition('name', 'field_test') - ->execute(); + module_set_weight('field_test', 1); } /** diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install index 8e6fddf..56f8402 100644 --- a/core/modules/forum/forum.install +++ b/core/modules/forum/forum.install @@ -10,10 +10,7 @@ */ function forum_install() { // Set the weight of the forum.module to 1 so it is loaded after the taxonomy.module. - db_update('system') - ->fields(array('weight' => 1)) - ->condition('name', 'forum') - ->execute(); + module_set_weight('forum', 1); // Forum topics are published by default, but do not have any other default // options set (for example, they are not promoted to the front page). // @todo Convert to default module configuration, once Node module's content diff --git a/core/modules/help/lib/Drupal/help/Tests/HelpTest.php b/core/modules/help/lib/Drupal/help/Tests/HelpTest.php index 0bd35e6..260768a 100644 --- a/core/modules/help/lib/Drupal/help/Tests/HelpTest.php +++ b/core/modules/help/lib/Drupal/help/Tests/HelpTest.php @@ -107,11 +107,10 @@ class HelpTest extends WebTestBase { */ protected function getModuleList() { $modules = array(); - $result = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC"); - foreach ($result as $module) { - if (file_exists($module->filename) && function_exists($module->name . '_help')) { - $fullname = unserialize($module->info); - $modules[$module->name] = $fullname['name']; + $module_data = system_rebuild_module_data(); + foreach (config('system.module')->get() as $module => $data) { + if (file_exists($module_data[$module]->filename) && function_exists($module . '_help')) { + $modules[$module] = $module_data[$module]->info['name']; } } return $modules; diff --git a/core/modules/locale/lib/Drupal/locale/LocaleLookup.php b/core/modules/locale/lib/Drupal/locale/LocaleLookup.php index 897eaa1..ea24417 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleLookup.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleLookup.php @@ -36,7 +36,16 @@ class LocaleLookup extends CacheArray { // Add the current user's role IDs to the cache key, this ensures that, for // example, strings for admin menu items and settings forms are not cached // for anonymous users. - $rids = implode(':', array_keys($GLOBALS['user']->roles)); + if (isset($GLOBALS['user'])) { + $rids = implode(':', array_keys($GLOBALS['user']->roles)); + } + else { + // If there is no global user, surely it's an anonymous user. For + // example, during update install_ensure_config_directory() calls for + // stream wrappers which calls locale_stream_wrappers() which has t() + // calls in it. + $rids = DRUPAL_ANONYMOUS_RID; + } parent::__construct("locale:$langcode:$context:$rids", 'cache'); } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.php index 2e85afa..323c55d 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.php @@ -47,6 +47,8 @@ class LocaleCompareTest extends WebTestBase { // modules not hidden. locale_test_system_info_alter() modifies the project // info of the locale_test and locale_test_disabled modules. variable_set('locale_translation_test_system_info_alter', TRUE); + // Reset system lists to reflect changes. + system_list_reset(); // Check if interface translation data is collected from hook_info. drupal_static_reset('locale_translation_project_list'); @@ -75,6 +77,8 @@ class LocaleCompareTest extends WebTestBase { // Return the locale test modules back to their hidden state. variable_del('locale_translation_test_system_info_alter'); + // Reset system lists to reflect changes. + system_list_reset(); } } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index 6370033..a10324e 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -122,6 +122,13 @@ abstract class TestBase { protected $verboseDirectory; /** + * The original database prefix when running inside Simpletest. + * + * @var string + */ + protected $originalPrefix; + + /** * Constructor for Test. * * @param $test_id @@ -742,6 +749,10 @@ abstract class TestBase { foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) { $GLOBALS['config_directories'][$type]['path'] = 'simpletest/' . substr($this->databasePrefix, 10) . '/config_' . $type; } + if (drupal_valid_test_ua()) { + $this->originalPrefix = drupal_valid_test_ua(); + drupal_valid_test_ua($this->databasePrefix); + } // Reset and create a new service container. $this->container = drupal_container(NULL, TRUE); @@ -820,7 +831,6 @@ abstract class TestBase { // Reset module list and module load status. module_list_reset(); - module_load_all(FALSE, TRUE); // Restore original in-memory configuration. $conf = $this->originalConf; @@ -829,6 +839,9 @@ abstract class TestBase { drupal_container($this->originalContainer); $language_interface = $this->originalLanguage; $GLOBALS['config_directories'] = $this->originalConfigDirectories; + if (isset($this->originalPrefix)) { + drupal_valid_test_ua($this->originalPrefix); + } // Restore original shutdown callbacks. $callbacks = &drupal_register_shutdown_function(); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 4d86f8d..3e44a6d 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -9,7 +9,6 @@ namespace Drupal\simpletest; use Drupal\Core\DrupalKernel; use Drupal\Core\Database\Database; -use Drupal\Core\Database\ConnectionNotDefinedException; use PDO; use stdClass; use DOMDocument; @@ -1067,7 +1066,8 @@ abstract class WebTestBase extends TestBase { // options set, it might change the GET into a POST. Make sure we clear out // previous options. $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers)); - $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up. + // Ensure that any changes to variables in the other thread are picked up. + $this->refreshVariables(); // Replace original page output with new output from redirected page(s). if ($new = $this->checkForMetaRefresh()) { diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module index dd5ee4d..98b62c9 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -1,6 +1,7 @@ fetchAllKeyed(); - foreach ($system_list as $name => $filename) { + foreach ($module_data as $name => $data) { + $dirname = dirname($data->filename); // Build directory in which the test files would reside. - $tests_dir = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/Drupal/' . $name . '/Tests'; + $tests_dir = DRUPAL_ROOT . '/' . $dirname . '/lib/Drupal/' . $name . '/Tests'; // Scan it for test files if it exists. if (is_dir($tests_dir)) { $files = file_scan_directory($tests_dir, '/.*\.php/'); if (!empty($files)) { - $basedir = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/'; + $basedir = DRUPAL_ROOT . '/' . $dirname . '/lib/'; foreach ($files as $file) { // Convert the file name into the namespaced class name. $replacements = array( @@ -357,7 +362,7 @@ function simpletest_test_get_all() { // If this test class requires a non-existing module, skip it. if (!empty($info['dependencies'])) { foreach ($info['dependencies'] as $module) { - if (!drupal_get_filename('module', $module)) { + if (!isset($module_data[$module])) { continue 2; } } @@ -384,16 +389,21 @@ function simpletest_test_get_all() { /** * Registers namespaces for disabled modules. */ -function simpletest_classloader_register() { - // Get the cached test modules list and register a test namespace for each. - $disabled_modules = db_query("SELECT name, filename FROM {system} WHERE status = 0")->fetchAllKeyed(); - if ($disabled_modules) { - foreach ($disabled_modules as $name => $filename) { - drupal_classloader_register($name, dirname($filename)); - } +function simpletest_classloader_register($module_data = NULL) { + if (!$module_data) { + // This is only needed to register namespaces and it is safe to + // re-register existing namespaces so go with raw data. + $module_data = _system_rebuild_module_data('simpletest_module_data'); + } + foreach ($module_data as $name => $data) { + drupal_classloader_register($name, dirname($data->filename)); } } +function simpletest_prepare_module_data() { + _system_rebuild_module_data('simpletest_module_data', TRUE); +} + /** * Generate test file. */ diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php index 4b15603..f85750b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php @@ -34,11 +34,11 @@ class RangeQueryTest extends WebTestBase { */ function testRangeQuery() { // Test if return correct number of rows. - $range_rows = db_query_range("SELECT name FROM {system} ORDER BY name", 2, 3)->fetchAll(); + $range_rows = db_query_range("SELECT name FROM {variable} ORDER BY name", 2, 3)->fetchAll(); $this->assertEqual(count($range_rows), 3, 'Range query work and return correct number of rows.'); // Test if return target data. - $raw_rows = db_query('SELECT name FROM {system} ORDER BY name')->fetchAll(); + $raw_rows = db_query('SELECT name FROM {variable} ORDER BY name')->fetchAll(); $raw_rows = array_slice($raw_rows, 2, 3); $this->assertEqual($range_rows, $raw_rows, 'Range query work and return target data.'); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/TemporaryQueryTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/TemporaryQueryTest.php index dab4a70..110f5a8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Database/TemporaryQueryTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Database/TemporaryQueryTest.php @@ -43,7 +43,7 @@ class TemporaryQueryTest extends WebTestBase { $this->drupalGet('database_test/db_query_temporary'); $data = json_decode($this->drupalGetContent()); if ($data) { - $this->assertEqual($this->countTableRows("system"), $data->row_count, 'The temporary table contains the correct amount of rows.'); + $this->assertEqual($this->countTableRows("filter"), $data->row_count, 'The temporary table contains the correct amount of rows.'); $this->assertFalse(db_table_exists($data->table_name), 'The temporary table is, indeed, temporary.'); } else { @@ -51,10 +51,10 @@ class TemporaryQueryTest extends WebTestBase { } // Now try to run two db_query_temporary() in the same request. - $table_name_system = db_query_temporary('SELECT status FROM {system}', array()); + $table_name_system = db_query_temporary('SELECT name FROM {variable}', array()); $table_name_users = db_query_temporary('SELECT uid FROM {users}', array()); - $this->assertEqual($this->countTableRows($table_name_system), $this->countTableRows("system"), 'A temporary table was created successfully in this request.'); + $this->assertEqual($this->countTableRows($table_name_system), $this->countTableRows("variable"), 'A temporary table was created successfully in this request.'); $this->assertEqual($this->countTableRows($table_name_users), $this->countTableRows("users"), 'A second temporary table was created successfully in this request.'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php index 75070a9..70de01d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php @@ -49,11 +49,7 @@ class ModuleApiTest extends WebTestBase { $this->assertModuleList($module_list, t('After adding a module')); // Try to mess with the module weights. - db_update('system') - ->fields(array('weight' => 20)) - ->condition('name', 'contact') - ->condition('type', 'module') - ->execute(); + module_set_weight('contact', 20); // Reset the module list. system_list_reset(); // Move contact to the end of the array. diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php index e328712..6867ae8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php @@ -62,9 +62,8 @@ class VersionTest extends ModuleTestBase { // Testing extra version. Incompatible. 'common_test (>2.4-rc0)', ); - variable_set('dependencies', $dependencies); - $n = count($dependencies); - for ($i = 0; $i < $n; $i++) { + foreach ($dependencies as $i => $dependency) { + variable_set('dependency', $dependency); $this->drupalGet('admin/modules'); $checkbox = $this->xpath('//input[@id="edit-modules-testing-module-test-enable"]'); $this->assertEqual(!empty($checkbox[0]['disabled']), $i % 2, $dependencies[$i]); diff --git a/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php b/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php index 9bdeac4..603af18 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php @@ -27,13 +27,14 @@ class InfoAlterTest extends WebTestBase { * return freshly altered info. */ function testSystemInfoAlter() { - // Enable our test module. Flush all caches, which we assert is the only - // thing necessary to use the rebuilt {system}.info. + // Enable seven and the test module. Flush all caches, which we assert is + // the only thing necessary to use the rebuilt {system}.info. + theme_enable(array('seven')); module_enable(array('module_test'), FALSE); $this->resetAll(); $this->assertTrue(module_exists('module_test'), t('Test module is enabled.')); - $info = $this->getSystemInfo('seven', 'theme'); + $info = system_get_info('theme', 'seven'); $this->assertTrue(isset($info['regions']['test_region']), t('Altered theme info was added to {system}.info.')); $seven_regions = system_region_list('seven'); $this->assertTrue(isset($seven_regions['test_region']), t('Altered theme info was returned by system_region_list().')); @@ -48,7 +49,7 @@ class InfoAlterTest extends WebTestBase { $this->resetAll(); $this->assertFalse(module_exists('module_test'), t('Test module is disabled.')); - $info = $this->getSystemInfo('seven', 'theme'); + $info = system_get_info('theme', 'seven'); $this->assertFalse(isset($info['regions']['test_region']), t('Altered theme info was removed from {system}.info.')); $seven_regions = system_region_list('seven'); $this->assertFalse(isset($seven_regions['test_region']), t('Altered theme info was not returned by system_region_list().')); @@ -58,20 +59,4 @@ class InfoAlterTest extends WebTestBase { $list_themes = list_themes(); $this->assertFalse(isset($list_themes['seven']->info['regions']['test_region']), t('Altered theme info was not returned by list_themes().')); } - - /** - * Returns the info array as it is stored in {system}. - * - * @param $name - * The name of the record in {system}. - * @param $type - * The type of record in {system}. - * - * @return - * Array of info, or FALSE if the record is not found. - */ - function getSystemInfo($name, $type) { - $raw_info = db_query("SELECT info FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField(); - return $raw_info ? unserialize($raw_info) : FALSE; - } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php index 1231af4..918eb96 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php @@ -129,10 +129,10 @@ class UpdateScriptTest extends WebTestBase { // Since visiting update.php triggers a rebuild of the theme system from an // unusual maintenance mode environment, we check that this rebuild did not // put any incorrect information about the themes into the database. - $original_theme_data = db_query("SELECT * FROM {system} WHERE type = 'theme' ORDER BY name")->fetchAll(); + $original_theme_data = config('system.theme')->get(); $this->drupalLogin($this->update_user); $this->drupalGet($this->update_url, array('external' => TRUE)); - $final_theme_data = db_query("SELECT * FROM {system} WHERE type = 'theme' ORDER BY name")->fetchAll(); + $final_theme_data = config('system.theme')->get(); $this->assertEqual($original_theme_data, $final_theme_data, t('Visiting update.php does not alter the information about themes stored in the database.')); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php index 812bde7..2c64b08 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php @@ -189,8 +189,7 @@ abstract class UpgradePathTestBase extends WebTestBase { protected function performUpgrade($register_errors = TRUE) { // Load the first update screen. - $update_url = $GLOBALS['base_url'] . '/core/update.php'; - $this->drupalGet($update_url, array('external' => TRUE)); + $this->getUpdatePhp(); if (!$this->assertResponse(200)) { throw new Exception('Initial GET to update.php did not return HTTP 200 status.'); } @@ -230,7 +229,7 @@ abstract class UpgradePathTestBase extends WebTestBase { } // Check if there still are pending updates. - $this->drupalGet($update_url, array('external' => TRUE)); + $this->getUpdatePhp(); $this->drupalPost(NULL, array(), t('Continue')); if (!$this->assertText(t('No pending updates.'), t('No pending updates at the end of the update process.'))) { throw new Exception('update.php still shows pending updates after execution.'); @@ -244,7 +243,6 @@ abstract class UpgradePathTestBase extends WebTestBase { // but not on the test client. system_list_reset(); module_implements_reset(); - module_load_all(FALSE, TRUE); // Rebuild caches. // @todo Remove the try/catch when UpgradePathTestBase::setup() is fixed to @@ -264,21 +262,27 @@ abstract class UpgradePathTestBase extends WebTestBase { } /** - * Force uninstall all modules from a test database, except those listed. + * Gets update.php without calling url(). * - * @param $modules - * The list of modules to keep installed. Required core modules will - * always be kept. + * This function is necessary because drupalGet calls t() before the + * database is ready for that. */ - protected function uninstallModulesExcept(array $modules) { - $required_modules = array('block', 'dblog', 'filter', 'node', 'system', 'update', 'user'); - - $modules = array_merge($required_modules, $modules); + protected function getUpdatePhp() { + // We re-using a CURL connection here. If that connection still has certain + // options set, it might change the GET into a POST. Make sure we clear out + // previous options. + $path = $GLOBALS['base_url'] . '/core/update.php'; + $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $path, CURLOPT_NOBODY => FALSE)); + // Ensure that any changes to variables in the other thread are picked up. + $this->refreshVariables(); - db_delete('system') - ->condition('type', 'module') - ->condition('name', $modules, 'NOT IN') - ->execute(); + // Replace original page output with new output from redirected page(s). + if ($new = $this->checkForMetaRefresh()) { + $out = $new; + } + $this->verbose('GET request to: update.php' . + '