diff --git a/core/includes/module.inc b/core/includes/module.inc index 6b4604a..29c9712 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -105,6 +105,7 @@ function module_list($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE } else { // Not using drupal_map_assoc() here as that requires common.inc. + // @todo MEH @ array_keys() $list = array_keys(system_list('module_enabled')); $list = (!empty($list) ? array_combine($list, $list) : array()); } @@ -139,6 +140,7 @@ function module_list($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE * @see list_themes() */ function system_list($type) { + // @todo Drop this cache as soon as config caches already. $lists = &drupal_static(__FUNCTION__); // For bootstrap modules, attempt to fetch the list from cache if possible. @@ -168,7 +170,7 @@ function system_list($type) { } // Otherwise build the list for enabled modules and themes. elseif (!isset($lists['module_enabled'])) { - if ($cached = cache('bootstrap')->get('system_list')) { + if (0 && $cached = cache('bootstrap')->get('system_list')) { $lists = $cached->data; } else { @@ -177,55 +179,51 @@ function system_list($type) { 'theme' => array(), 'filepaths' => array(), ); + // 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) { - $record->info = unserialize($record->info); - // Build a list of all enabled modules. - if ($record->type == 'module') { - $lists['module_enabled'][$record->name] = $record; - } - // Build a list of themes. - if ($record->type == 'theme') { - $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); - } + // @todo ^^ NFIAA how to migrate that. ^^ + + // @todo Upgrade path. + $config_modules = config('system.modules'); + $lists['module_enabled'] = $config_modules->get('enabled'); + uasort($lists['module_enabled'], 'drupal_sort_weight'); + // @todo Fix calling code to not rely on a duplicated $name within $record. + // @todo Fix calling code to not assume that system_list() would ever return + // something disabled [status]. + // @todo Adjust calling code to use arrays instead of objects. + foreach ($lists['module_enabled'] as $name => $record) { + $record['name'] = $name; + $record['status'] = 1; + $lists['module_enabled'][$name] = (object) $record; + + $lists['filepaths'][] = array('type' => 'module', 'name' => $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. - $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']; + + $config_themes = config('system.themes'); + $lists['theme'] = $config_themes->get('enabled'); + uasort($lists['theme'], 'drupal_sort_weight'); + // @todo Fix calling code to not rely on a duplicated $name within $record. + // @todo Fix calling code to not assume that system_list() would ever return + // something disabled [status]. + // @todo Adjust calling code to use arrays instead of objects. + foreach ($lists['theme'] as $name => $record) { + $record['name'] = $name; + $record['status'] = 1; + $lists['theme'][$name] = (object) $record; + + $lists['filepaths'][] = array('type' => 'theme', 'name' => $name, 'filepath' => $record['filename']); } + cache('bootstrap')->set('system_list', $lists); } // To avoid a separate database lookup for the filepath, prime the // drupal_get_filename() static cache with all enabled modules and themes. + // @todo A separate cache is nuts for this. Can happy walk through 'module' + // and 'theme' keys instead. foreach ($lists['filepaths'] as $item) { drupal_get_filename($item['type'], $item['name'], $item['filepath']); drupal_classloader_register($item['name'], dirname($item['filepath'])); @@ -243,6 +241,7 @@ function system_list_reset() { drupal_static_reset('system_rebuild_module_data'); drupal_static_reset('list_themes'); cache('bootstrap')->deleteMultiple(array('bootstrap_modules', 'system_list')); + cache('bootstrap')->deletePrefix('system_info:'); } /** @@ -455,11 +454,12 @@ function module_enable($module_list, $enable_dependencies = TRUE) { // 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(); + config('system.modules')->set('enabled.' . $module, array( + 'filename' => drupal_get_filename('module', $module), + // @todo Need actual weight. + 'weight' => 0, + ))->save(); + // Refresh the module list to include it. system_list_reset(); module_list(TRUE); @@ -572,11 +572,9 @@ function module_disable($module_list, $disable_dependents = TRUE) { if (module_exists($module)) { module_load_install($module); module_invoke($module, 'disable'); - db_update('system') - ->fields(array('status' => 0)) - ->condition('type', 'module') - ->condition('name', $module) - ->execute(); + + config('system.modules')->clear('enabled.' . $module)->save(); + $invoke_modules[] = $module; watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO); } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 7d638f6..89de188 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -768,6 +768,33 @@ function list_themes($refresh = FALSE) { if (!defined('MAINTENANCE_MODE')) { try { $themes = system_list('theme'); + foreach ($themes as $name => $theme) { + $theme->info = system_get_info('theme', $name); + } + foreach ($themes as $name => $theme) { + if (!empty($theme->info['base theme'])) { + // Make a list of the theme's base themes. + $theme->base_themes = drupal_find_base_themes($themes, $name); + // Don't proceed if there was a problem with the root base theme. + if (!current($theme->base_themes)) { + continue; + } + // Determine the root base theme. + $base_key = key($theme->base_themes); + // Add to the list of sub-themes for each of the theme's base themes. + foreach (array_keys($theme->base_themes) as $base_theme) { + $themes[$base_theme]->sub_themes[$name] = $name; + } + // Add the base theme's theme engine info. + $theme->info['engine'] = $themes[$base_key]->info['engine']; + } + else { + // A plain theme is its own base theme. + $base_key = $name; + } + // Set the theme engine prefix. + $theme->prefix = ($theme->info['engine'] == 'theme') ? $base_key : $theme->info['engine']; + } } catch (Exception $e) { // If the database is not available, rebuild the theme data. @@ -1478,14 +1505,25 @@ function theme_render_template($template_file, $variables) { * An array of theme names. */ function theme_enable($theme_list) { + // @todo Why on earth is module_enable/_disable() not simply system_enable/_disable() ??! + // Lazy workaround to make system_theme_enable() happy. + $theme_data = system_rebuild_theme_data(); + foreach ($theme_list as $name) { + if (!isset($theme_data[$name])) { + // This theme is not found in the filesystem, abort. + return FALSE; + } + } + drupal_clear_css_cache(); - foreach ($theme_list as $key) { - db_update('system') - ->fields(array('status' => 1)) - ->condition('type', 'theme') - ->condition('name', $key) - ->execute(); + foreach ($theme_list as $name) { + config('system.themes')->set('enabled.' . $name, array( + 'filename' => drupal_get_filename('theme', $name), + 'owner' => $theme_data[$name]->owner, + // @todo Need actual weight. + 'weight' => $theme_data[$name]->weight, + ))->save(); } list_themes(TRUE); @@ -1494,6 +1532,7 @@ function theme_enable($theme_list) { // Invoke hook_themes_enabled() after the themes have been enabled. module_invoke_all('themes_enabled', $theme_list); + return TRUE; } /** @@ -1507,18 +1546,14 @@ function theme_disable($theme_list) { if ($pos = array_search(variable_get('theme_default', 'stark'), $theme_list) !== FALSE) { unset($theme_list[$pos]); if (empty($theme_list)) { - return; + return FALSE; } } drupal_clear_css_cache(); - foreach ($theme_list as $key) { - db_update('system') - ->fields(array('status' => 0)) - ->condition('type', 'theme') - ->condition('name', $key) - ->execute(); + foreach ($theme_list as $name) { + config('system.themes')->clear('enabled.' . $name)->save(); } list_themes(TRUE); @@ -1527,6 +1562,7 @@ function theme_disable($theme_list) { // Invoke hook_themes_disabled after the themes have been disabled. module_invoke_all('themes_disabled', $theme_list); + return TRUE; } /** diff --git a/core/includes/update.inc b/core/includes/update.inc index b0d09a7..d58573f 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -937,6 +937,46 @@ function update_variables_to_config($config_name, array $variable_map = array()) } } +/* Run me with the following from /debug.php or whatever: + +require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc'; +require_once DRUPAL_ROOT . '/core/includes/common.inc'; +require_once DRUPAL_ROOT . '/core/includes/update.inc'; +drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE); +update_system_list_to_config(); + +*/ +function update_system_list_to_config() { + // Migrate enabled modules and list of bootstrap modules. + $result = db_query("SELECT * FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, name ASC"); + $config = config('system.modules'); + $bootstrap = array(); + foreach ($result as $record) { + if ($record->bootstrap) { + $bootstrap[] = $record->name; + } + $config->set('enabled.' . $record->name, array( + 'filename' => $record->filename, + 'weight' => $record->weight, + )); + } + $config->set('bootstrap', $bootstrap); + $config->save(); + + // Migrate themes. + // Intentionally leaves out disabled themes. + $result = db_query("SELECT * FROM {system} WHERE type = 'theme' AND status = 1 ORDER BY weight ASC, name ASC"); + $config = config('system.themes'); + foreach ($result as $record) { + $config->set('enabled.' . $record->name, array( + 'filename' => $record->filename, + 'owner' => $record->owner, + 'weight' => $record->weight, + )); + } + $config->save(); +} + /** * @defgroup update-api-7.x-to-8.x Update versions of API functions * @{ diff --git a/core/lib/Drupal/Core/Config/DrupalConfig.php b/core/lib/Drupal/Core/Config/DrupalConfig.php index f5a9220..2875d74 100644 --- a/core/lib/Drupal/Core/Config/DrupalConfig.php +++ b/core/lib/Drupal/Core/Config/DrupalConfig.php @@ -201,6 +201,7 @@ class DrupalConfig { else { drupal_array_unset_nested_value($this->data, $parts); } + return $this; } /** diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index fc0e8bb..27e2cd4 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -265,12 +265,9 @@ function system_themes_admin_form_submit($form, &$form_state) { function system_theme_enable() { if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) { $theme = $_REQUEST['theme']; - // Get current list of themes. - $themes = list_themes(); - // Check if the specified theme is one recognized by the system. - if (!empty($themes[$theme])) { - theme_enable(array($theme)); + if (theme_enable(array($theme))) { + $themes = list_themes(); drupal_set_message(t('The %theme theme has been enabled.', array('%theme' => $themes[$theme]->info['name']))); } else { @@ -287,19 +284,14 @@ function system_theme_enable() { function system_theme_disable() { if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) { $theme = $_REQUEST['theme']; - // Get current list of themes. $themes = list_themes(); - // Check if the specified theme is one recognized by the system. - if (!empty($themes[$theme])) { - if ($theme == variable_get('theme_default', 'stark')) { - // Don't disable the default theme. - drupal_set_message(t('%theme is the default theme and cannot be disabled.', array('%theme' => $themes[$theme]->info['name'])), 'error'); - } - else { - theme_disable(array($theme)); - drupal_set_message(t('The %theme theme has been disabled.', array('%theme' => $themes[$theme]->info['name']))); - } + if ($theme == variable_get('theme_default', 'stark')) { + // Don't disable the default theme. + drupal_set_message(t('%theme is the default theme and cannot be disabled.', array('%theme' => $themes[$theme]->info['name'])), 'error'); + } + elseif (theme_disable(array($theme))) { + drupal_set_message(t('The %theme theme has been disabled.', array('%theme' => $themes[$theme]->info['name']))); } else { drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error'); diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 5581d01..a9b95f0 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1574,7 +1574,7 @@ function system_schema() { $schema['system'] = array( 'description' => "A list of all modules, themes, and theme engines that are or have been installed in Drupal's file system.", 'fields' => array( - 'filename' => array( + 'filename' => array( // obsolete. 'description' => 'The path of the primary file for this item, relative to the Drupal root; e.g. modules/node/node.module.', 'type' => 'varchar', 'length' => 255, @@ -1588,27 +1588,27 @@ function system_schema() { 'not null' => TRUE, 'default' => '', ), - 'type' => array( + 'type' => array( // obsolete. 'description' => 'The type of the item, either module, theme, or theme_engine.', 'type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => '', ), - 'owner' => array( + 'owner' => array( // obsolete. 'description' => "A theme's 'parent' . Can be either a theme or an engine.", 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), - 'status' => array( + 'status' => array( // obsolete. 'description' => 'Boolean indicating whether or not this item is enabled.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), - 'bootstrap' => array( + 'bootstrap' => array( // obsolete. 'description' => "Boolean indicating whether this module is loaded during Drupal's early bootstrapping phase (e.g. even before the page cache is consulted).", 'type' => 'int', 'not null' => TRUE, @@ -1621,7 +1621,7 @@ function system_schema() { 'default' => -1, 'size' => 'small', ), - 'weight' => array( + 'weight' => array( // obsolete. 'description' => "The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name.", 'type' => 'int', 'not null' => TRUE, diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 6e60da8..e62c0df 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2276,6 +2276,34 @@ function system_check_directory($form_element) { * The type of the files. */ function system_get_files_database(&$files, $type) { + // Handle config. + // @todo Rename system.modules/themes into singular. + $config = config('system.' . $type . 's')->get('enabled'); +// foreach ($config as $name => $record) { +// $record['name'] = $name; +// $record['status'] = 1; +// +// foreach ($record as $key => $value) { +// if (!isset($files[$name]->$key)) { +// $files[$name]->$key = $value; +// } +// } +// } + // Let's reverse it: + // Whatever is in config is enabled. Whatever is not in config is disabled. + // And for disabled stuff, we don't care. At all. + foreach ($files as $name => $file) { + if (isset($config[$name])) { + $file->status = 1; + $file->filename = $file->uri = $config[$name]['filename']; + $file->weight = $config[$name]['weight']; + } + else { + $file->status = 0; + } + } + + // Handle {system}... // Extract current files from database. $result = db_query("SELECT filename, name, type, status, schema_version, weight FROM {system} WHERE type = :type", array(':type' => $type)); foreach ($result as $file) { @@ -2400,20 +2428,39 @@ function system_update_files_database(&$files, $type) { * @see system_rebuild_theme_data() */ function system_get_info($type, $name = NULL) { + $list = &drupal_static(__FUNCTION__, array()); + $info = array(); - if ($type == 'module') { - $type = 'module_enabled'; - } - $list = system_list($type); - foreach ($list as $shortname => $item) { - if (!empty($item->status)) { - $info[$shortname] = $item->info; + + if (!isset($list[$type])) { + $system_list_type = ($type == 'module' ? 'module_enabled' : $type); + $system_list = system_list($system_list_type); + // @todo Remove value. + foreach ($system_list as $extension => $whatever_dont_use_me) { + $cid = 'system_info:' . $extension; + if (0 && $cached = cache('bootstrap')->get($cid)) { + $list[$type][$extension] = $cached->data; + } + else { + $info = db_query_range("SELECT info FROM {system} WHERE type = :type AND name = :name", 0, 1, array( + ':type' => $type, + ':name' => $extension, + ))->fetchField(); + // Account for non-existing {system} record. (shouldn't be possible) + $info = ($info ? unserialize($info) : array()); + // Account for bogus {system}.info data. (shouldn't be possible) + $info = ($info ? $info : array()); + + cache('bootstrap')->set($cid, $info); + $list[$type][$extension] = $info; + } } } + if (isset($name)) { - return isset($info[$name]) ? $info[$name] : array(); + return isset($list[$type][$name]) ? $list[$type][$name] : array(); } - return $info; + return $list[$type]; } /** diff --git a/core/modules/system/system.test b/core/modules/system/system.test index ec1a9a6..59de7b4 100644 --- a/core/modules/system/system.test +++ b/core/modules/system/system.test @@ -2195,8 +2195,7 @@ class SystemInfoAlterTestCase extends WebTestBase { $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().')); - $system_list_themes = system_list('theme'); - $info = $system_list_themes['seven']->info; + $info = system_get_info('theme', 'seven'); $this->assertTrue(isset($info['regions']['test_region']), t('Altered theme info was returned by system_list().')); $list_themes = list_themes(); $this->assertTrue(isset($list_themes['seven']->info['regions']['test_region']), t('Altered theme info was returned by list_themes().')); @@ -2210,8 +2209,7 @@ class SystemInfoAlterTestCase extends WebTestBase { $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().')); - $system_list_themes = system_list('theme'); - $info = $system_list_themes['seven']->info; + $info = system_get_info('theme', 'seven'); $this->assertFalse(isset($info['regions']['test_region']), t('Altered theme info was not returned by system_list().')); $list_themes = list_themes(); $this->assertFalse(isset($list_themes['seven']->info['regions']['test_region']), t('Altered theme info was not returned by list_themes().'));