diff --git a/core/authorize.php b/core/authorize.php index 114dcd3ad1de632ab577955c7a52160e485a70b7..46c6a29a3e2a4e8f4eb2c2fcab059ba4fea83a2f 100644 --- a/core/authorize.php +++ b/core/authorize.php @@ -78,11 +78,11 @@ function authorize_access_allowed() { // We have to enable the user and system modules, even to check access and // display errors via the maintenance theme. -$module_list['system'] = 'core/modules/system/system.module'; -$module_list['user'] = 'core/modules/user/user.module'; -drupal_container()->get('module_handler')->setModuleList($module_list); -drupal_container()->get('module_handler')->load('system'); -drupal_container()->get('module_handler')->load('user'); +$module_list['system']['filename'] = 'core/modules/system/system.module'; +$module_list['user']['filename'] = 'core/modules/user/user.module'; +module_list(NULL, $module_list); +drupal_load('module', 'system'); +drupal_load('module', 'user'); // Initialize the language system. drupal_language_initialize(); diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index d4f32e182aaf666227ef727882d0dbd9d7317d70..577d857b9b411f898fc9655a80f49aaef426b12f 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -888,14 +888,6 @@ function drupal_get_filename($type, $name, $filename = NULL) { // nothing } else { - if ($type == 'module') { - if (empty($files[$type])) { - $files[$type] = drupal_container()->get('module_handler')->getModuleList(); - } - if (isset($files[$type][$name])) { - return $files[$type][$name]; - } - } // Verify that we have an keyvalue service before using it. This is required // because this function is called during installation. // @todo Inject database connection into KeyValueStore\DatabaseStorage. @@ -1141,9 +1133,8 @@ function drupal_page_is_cacheable($allow_caching = NULL) { * @see bootstrap_hooks() */ function bootstrap_invoke_all($hook) { - $module_handler = drupal_container()->get('module_handler'); - foreach ($module_handler->getBootstrapModules() as $module) { - $module_handler->load($module); + foreach (module_list('bootstrap') as $module) { + drupal_load('module', $module); module_invoke($module, $hook); } } @@ -1162,10 +1153,6 @@ function bootstrap_invoke_all($hook) { * TRUE if the item is loaded or has already been loaded. */ function drupal_load($type, $name) { - if ($type == 'module' && drupal_container()->get('module_handler')->moduleExists($name)) { - return drupal_container()->get('module_handler')->load($name); - } - // Once a file is included this can't be reversed during a request so do not // use drupal_static() here. static $files = array(); @@ -2436,7 +2423,7 @@ function _drupal_bootstrap_variables() { $conf = variable_initialize(isset($conf) ? $conf : array()); // Load bootstrap modules. require_once DRUPAL_ROOT . '/core/includes/module.inc'; - drupal_container()->get('module_handler')->loadBootstrapModules(); + module_load_all(TRUE); } /** @@ -2489,82 +2476,6 @@ function drupal_container(ContainerInterface $new_container = NULL) { return $container; } -/** - * Returns the list of enabled modules. - * - * @deprecated as of Drupal 8.0. Use - * drupal_container()->get('module_handler')->getModuleList(). - * - * @see \Drupal\Core\Extension\ModuleHandler::getModuleList() - */ -function module_list() { - $modules = array_keys(drupal_container()->get('module_handler')->getModuleList()); - return array_combine($modules, $modules); -} - -/** - * Determines which modules are implementing a hook. - * - * @deprecated as of Drupal 8.0. Use - * drupal_container()->get('module_handler')->getImplementations($hook). - * - * @see \Drupal\Core\Extension\ModuleHandler::getImplementations() - */ -function module_implements($hook) { - return drupal_container()->get('module_handler')->getImplementations($hook); -} - -/** - * Invokes a hook in all enabled modules that implement it. - * - * @deprecated as of Drupal 8.0. Use - * drupal_container()->get('module_handler')->invokeAll($hook). - * - * @see \Drupal\Core\Extension\ModuleHandler::invokeAll() - */ -function module_invoke_all($hook) { - $args = func_get_args(); - // Remove $hook from the arguments. - array_shift($args); - return drupal_container()->get('module_handler')->invokeAll($hook, $args); -} - -/** - * Passes alterable variables to specific hook_TYPE_alter() implementations. - * - * @deprecated as of Drupal 8.0. Use - * drupal_container()->get('module_handler')->alter($hook). - * - * @see \Drupal\Core\Extension\ModuleHandler::alter() - */ -function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { - return drupal_container()->get('module_handler')->alter($type, $data, $context1, $context2); -} - -/** - * Determines whether a given module exists. - * - * @deprecated as of Drupal 8.0. Use - * drupal_container()->get('module_handler')->moduleExists($hook). - * - * @see \Drupal\Core\Extension\ModuleHandler::moduleExists() - */ -function module_exists($module) { - return drupal_container()->get('module_handler')->moduleExists($module); -} - -/** - * Determines whether a module implements a hook. - * - * @deprecated as of Drupal 8.0. Use - * drupal_container()->get('module_handler')->implementsHook($module, $hook). - * - * @see \Drupal\Core\Extension\ModuleHandler::implementsHook() - */ -function module_hook($module, $hook) { - return drupal_container()->get('module_handler')->implementsHook($module, $hook); -} - /** * Returns the state storage service. * diff --git a/core/includes/common.inc b/core/includes/common.inc index 0c16ac913a6b2a4f5cbe870cd558dd136e8ca42d..d97ef30107d9eecc5e32f222e564bd41f1a810f0 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4839,7 +4839,7 @@ function _drupal_bootstrap_code() { require_once DRUPAL_ROOT . '/core/includes/entity.inc'; // Load all enabled modules - drupal_container()->get('module_handler')->loadAll(); + module_load_all(); // Make sure all stream wrappers are registered. file_get_stream_wrappers(); @@ -6438,7 +6438,7 @@ function drupal_flush_all_caches() { // Ensure that all modules that are currently supposed to be enabled are // actually loaded. - drupal_container()->get('module_handler')->loadAll(); + module_load_all(); // Update the list of bootstrap modules. // Allows developers to get new hook_boot() implementations registered without @@ -6511,11 +6511,69 @@ function debug($data, $label = NULL, $print_r = FALSE) { trigger_error(trim($label ? "$label: $string" : $string)); } +/** + * Parses a dependency for comparison by drupal_check_incompatibility(). + * + * @param $dependency + * A dependency string, for example 'foo (>=8.x-4.5-beta5, 3.x)'. + * + * @return + * An associative array with three keys: + * - 'name' includes the name of the thing to depend on (e.g. 'foo'). + * - 'original_version' contains the original version string (which can be + * used in the UI for reporting incompatibilities). + * - 'versions' is a list of associative arrays, each containing the keys + * 'op' and 'version'. 'op' can be one of: '=', '==', '!=', '<>', '<', + * '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'. + * Callers should pass this structure to drupal_check_incompatibility(). + * + * @see drupal_check_incompatibility() + */ +function drupal_parse_dependency($dependency) { + // We use named subpatterns and support every op that version_compare + // supports. Also, op is optional and defaults to equals. + $p_op = '(?P!=|==|=|<|<=|>|>=|<>)?'; + // Core version is always optional: 8.x-2.x and 2.x is treated the same. + $p_core = '(?:' . preg_quote(DRUPAL_CORE_COMPATIBILITY) . '-)?'; + $p_major = '(?P\d+)'; + // By setting the minor version to x, branches can be matched. + $p_minor = '(?P(?:\d+|x)(?:-[A-Za-z]+\d+)?)'; + $value = array(); + $parts = explode('(', $dependency, 2); + $value['name'] = trim($parts[0]); + if (isset($parts[1])) { + $value['original_version'] = ' (' . $parts[1]; + foreach (explode(',', $parts[1]) as $version) { + if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) { + $op = !empty($matches['operation']) ? $matches['operation'] : '='; + if ($matches['minor'] == 'x') { + // Drupal considers "2.x" to mean any version that begins with + // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(), + // on the other hand, treats "x" as a string; so to + // version_compare(), "2.x" is considered less than 2.0. This + // means that >=2.x and <2.x are handled by version_compare() + // as we need, but > and <= are not. + if ($op == '>' || $op == '<=') { + $matches['major']++; + } + // Equivalence can be checked by adding two restrictions. + if ($op == '=' || $op == '==') { + $value['versions'][] = array('op' => '<', 'version' => ($matches['major'] + 1) . '.x'); + $op = '>='; + } + } + $value['versions'][] = array('op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']); + } + } + } + return $value; +} + /** * Checks whether a version is compatible with a given dependency. * * @param $v - * A parsed dependency structure e.g. from ModuleHandler::parseDependency(). + * The parsed dependency structure from drupal_parse_dependency(). * @param $current_version * The version to check against (like 4.2). * @@ -6523,7 +6581,7 @@ function debug($data, $label = NULL, $print_r = FALSE) { * NULL if compatible, otherwise the original dependency version string that * caused the incompatibility. * - * @see \Drupal\Core\Extension\ModuleHandler::parseDependency() + * @see drupal_parse_dependency() */ function drupal_check_incompatibility($v, $current_version) { if (!empty($v['versions'])) { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 20c690bef35f3178e67b321e3c971af379a93919..7f4b26b0980550be6ce5545334a68c0804e7381e 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -338,7 +338,6 @@ function install_begin_request(&$install_state) { $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') ->addArgument(new Reference('config.storage')) ->addArgument(new Reference('event_dispatcher')); - // The install process cannot use the database lock backend since the database // is not fully up, so we use a null backend implementation during the // installation process. This will also speed up the installation process. @@ -347,10 +346,6 @@ function install_begin_request(&$install_state) { // (as opposed to the cache backend) so we can afford having a null // implementation here. $container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); - - // Register a module handler for managing enabled modules. - $container - ->register('module_handler', 'Drupal\Core\Extension\ModuleHandler'); drupal_container($container); } @@ -358,13 +353,10 @@ function install_begin_request(&$install_state) { drupal_language_initialize(); require_once DRUPAL_ROOT . '/core/includes/ajax.inc'; - - $module_handler = drupal_container()->get('module_handler'); - if (!$module_handler->moduleExists('system')) { - // Override the module list with a minimal set of modules. - $module_handler->setModuleList(array('system' => 'core/modules/system/system.module')); - } - $module_handler->load('system'); + // Override the module list with a minimal set of modules. + $module_list['system']['filename'] = 'core/modules/system/system.module'; + module_list(NULL, $module_list); + drupal_load('module', 'system'); require_once DRUPAL_ROOT . '/core/includes/cache.inc'; $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend'); @@ -1578,7 +1570,9 @@ function install_bootstrap_full(&$install_state) { // cache backend will be used again. unset($GLOBALS['conf']['cache_classes']['cache']); drupal_static_reset('cache'); - + // Clear the module list that was overriden earlier in the process. + // This will allow all freshly installed modules to be loaded. + module_list_reset(); drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); } diff --git a/core/includes/install.inc b/core/includes/install.inc index e9d666f0657bf52480901171edb7c10b7748f0e7..9223b9c8d2d3c1979af07d344611c4f9c3074668 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -424,10 +424,15 @@ function drupal_install_system() { ->set('enabled.system', 0) ->save(); - // Update the module list to include it. - drupal_container()->get('module_handler')->setModuleList(array('system' => $system_path . '/system.module')); - drupal_container()->get('module_handler')->resetImplementations(); - + // Clear out module list and hook implementation statics. + system_list_reset(); + module_list_reset(); + module_implements_reset(); + + // To ensure that the system module can be found by the plugin system, warm + // the module list cache. + // @todo Remove this in http://drupal.org/node/1798732. + module_list(); config_install_default_config('module', 'system'); module_invoke('system', 'install'); diff --git a/core/includes/module.inc b/core/includes/module.inc index 83a3ba625ea2349d9241a24fbb59333787bd84e4..f6d47b6f164709e61e8b6e08a799e58f899b42c8 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -9,6 +9,114 @@ use Drupal\Component\Utility\NestedArray; use Symfony\Component\DependencyInjection\ContainerInterface; +/** + * Loads all enabled modules. + * + * @param bool $bootstrap + * 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) { + 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'; + foreach (module_list($type) as $module) { + drupal_load('module', $module); + } + // $has_run will be TRUE if $bootstrap is FALSE. + $has_run = !$bootstrap; + } + return $has_run; +} + +/** + * Returns a list of currently active modules. + * + * Acts as a wrapper around system_list(), returning either a list of all + * enabled modules, or just modules needed for bootstrap. + * + * The returned module list is always based on system_list(). The only exception + * to that is when a fixed list of modules has been passed in previously, in + * which case system_list() is omitted and the fixed list is always returned in + * subsequent calls until manually reverted via module_list_reset(). + * + * @param string $type + * The type of list to return: + * - module_enabled: All enabled modules. + * - bootstrap: All enabled modules required for bootstrap. + * @param array $fixed_list + * (optional) An array of module names to override the list of modules. This + * list will persist until the next call with a new $fixed_list passed in. + * Primarily intended for internal use (e.g., in install.php and update.php). + * Use module_list_reset() to undo the $fixed_list override. + * @param bool $reset + * (optional) Whether to reset/remove the $fixed_list. + * + * @return array + * An associative array whose keys and values are the names of the modules in + * the list. + * + * @see module_list_reset() + */ +function module_list($type = 'module_enabled', array $fixed_list = NULL, $reset = FALSE) { + // This static is only used for $fixed_list. It must not be a drupal_static(), + // since any call to drupal_static_reset() in unit tests would cause an + // attempt to retrieve the list of modules from the database (which does not + // exist). + static $module_list; + + if ($reset) { + $module_list = NULL; + // Do nothing if no $type and no $fixed_list have been passed. + if (!isset($type) && !isset($fixed_list)) { + return; + } + } + + // The list that will be be returned. Separate from $module_list in order + // to not duplicate the static cache of system_list(). + $list = $module_list; + + if (isset($fixed_list)) { + $module_list = array(); + foreach ($fixed_list as $name => $module) { + system_register('module', $name, $module['filename']); + $module_list[$name] = $name; + } + $list = $module_list; + } + elseif (!isset($module_list)) { + $list = system_list($type); + } + return $list; +} + +/** + * Reverts an enforced fixed list of module_list(). + * + * Subsequent calls to module_list() will no longer use a fixed list. + */ +function module_list_reset() { + module_list(NULL, NULL, TRUE); +} + /** * Builds a list of bootstrap modules and enabled modules and themes. * @@ -24,6 +132,7 @@ * For $type 'theme', the array values are objects representing the * respective database row, with the 'info' property already unserialized. * + * @see module_list() * @see list_themes() * * @todo There are too many layers/levels of caching involved for system_list() @@ -33,74 +142,121 @@ */ function system_list($type) { $lists = &drupal_static(__FUNCTION__); - if ($cached = cache('bootstrap')->get('system_list')) { - $lists = $cached->data; + + // For bootstrap modules, attempt to fetch the list from cache if possible. + // if not fetch only the required information to fire bootstrap hooks + // in case we are going to serve the page from cache. + if ($type == 'bootstrap') { + if (isset($lists['bootstrap'])) { + return $lists['bootstrap']; + } + if ($cached = cache('bootstrap')->get('bootstrap_modules')) { + $bootstrap_list = $cached->data; + } + else { + $bootstrap_list = state()->get('system.module.bootstrap') ?: array(); + 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 $name => $filename) { + system_register('module', $name, $filename); + } + // We only return the module names here since module_list() doesn't need + // the filename itself. + $lists['bootstrap'] = array_keys($bootstrap_list); } - else { - $lists = array( - 'theme' => array(), - 'filepaths' => array(), - ); - // Build a list of themes. - $enabled_themes = (array) config('system.theme')->get('enabled'); - // @todo Themes include all themes, including disabled/uninstalled. This - // system.theme.data state will go away entirely as soon as themes have - // a proper installation status. - // @see http://drupal.org/node/1067408 - $theme_data = state()->get('system.theme.data'); - if (empty($theme_data)) { - // @todo: system_list() may be called from _drupal_bootstrap_code(), in - // which case system.module is not loaded yet. - // Prevent a filesystem scan in drupal_load() and include it directly. - // @see http://drupal.org/node/1067408 - require_once DRUPAL_ROOT . '/core/modules/system/system.module'; - $theme_data = system_rebuild_theme_data(); - } - foreach ($theme_data as $name => $theme) { - $theme->status = (int) isset($enabled_themes[$name]); - $lists['theme'][$name] = $theme; - // Build a list of filenames so drupal_get_filename can use it. - if (isset($enabled_themes[$name])) { + // Otherwise build the list for enabled modules and themes. + elseif (!isset($lists['module_enabled'])) { + if ($cached = cache('bootstrap')->get('system_list')) { + $lists = $cached->data; + } + else { + $lists = array( + 'module_enabled' => array(), + '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(). + $enabled_modules = (array) config('system.module')->get('enabled'); + $module_files = state()->get('system.module.files'); + foreach ($enabled_modules as $name => $weight) { + // Build a list of all enabled modules. + $lists['module_enabled'][$name] = $name; + // Build a list of filenames so drupal_get_filename can use it. $lists['filepaths'][] = array( - 'type' => 'theme', + 'type' => 'module', 'name' => $name, - 'filepath' => $theme->filename, + 'filepath' => $module_files[$name], ); } - } - // @todo Move into list_themes(). Read info for a particular requested - // theme from state instead. - 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']; + + // Build a list of themes. + $enabled_themes = (array) config('system.theme')->get('enabled'); + // @todo Themes include all themes, including disabled/uninstalled. This + // system.theme.data state will go away entirely as soon as themes have + // a proper installation status. + // @see http://drupal.org/node/1067408 + $theme_data = state()->get('system.theme.data'); + if (empty($theme_data)) { + // @todo: system_list() may be called from _drupal_bootstrap_code() and + // module_load_all(), in which case system.module is not loaded yet. + // Prevent a filesystem scan in drupal_load() and include it directly. + // @see http://drupal.org/node/1067408 + require_once DRUPAL_ROOT . '/core/modules/system/system.module'; + $theme_data = system_rebuild_theme_data(); + } + foreach ($theme_data as $name => $theme) { + $theme->status = (int) isset($enabled_themes[$name]); + $lists['theme'][$name] = $theme; + // Build a list of filenames so drupal_get_filename can use it. + if (isset($enabled_themes[$name])) { + $lists['filepaths'][] = array( + 'type' => 'theme', + 'name' => $name, + 'filepath' => $theme->filename, + ); } - // 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; + // @todo Move into list_themes(). Read info for a particular requested + // theme from state instead. + 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']; } - // Set the theme engine prefix. - $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine']; + 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. + foreach ($lists['filepaths'] as $item) { + system_register($item['type'], $item['name'], $item['filepath']); } - 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. - foreach ($lists['filepaths'] as $item) { - system_register($item['type'], $item['name'], $item['filepath']); } return $lists[$type]; @@ -113,7 +269,7 @@ function system_list_reset() { drupal_static_reset('system_list'); drupal_static_reset('system_rebuild_module_data'); drupal_static_reset('list_themes'); - cache('bootstrap')->delete('system_list'); + cache('bootstrap')->deleteMultiple(array('bootstrap_modules', 'system_list')); cache()->delete('system_info'); // Remove last known theme data state. // This causes system_list() to call system_rebuild_theme_data() on its next @@ -141,6 +297,53 @@ function system_register($type, $name, $uri) { drupal_classloader_register($name, dirname($uri)); } +/** + * Determines which modules require and are required by each module. + * + * @param $files + * The array of filesystem objects used to rebuild the cache. + * + * @return + * The same array with the new keys for each module: + * - requires: An array with the keys being the modules that this module + * requires. + * - required_by: An array with the keys being the modules that will not work + * without this module. + */ +function _module_build_dependencies($files) { + foreach ($files as $filename => $file) { + $graph[$file->name]['edges'] = array(); + if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) { + foreach ($file->info['dependencies'] as $dependency) { + $dependency_data = drupal_parse_dependency($dependency); + $graph[$file->name]['edges'][$dependency_data['name']] = $dependency_data; + } + } + } + $graph_object = new Graph($graph); + $graph = $graph_object->searchAndSort(); + foreach ($graph as $module => $data) { + $files[$module]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array(); + $files[$module]->requires = isset($data['paths']) ? $data['paths'] : array(); + $files[$module]->sort = $data['weight']; + } + return $files; +} + +/** + * Determines whether a given module exists. + * + * @param $module + * The name of the module (without the .module extension). + * + * @return + * TRUE if the module is both installed and enabled. + */ +function module_exists($module) { + $list = module_list(); + return isset($list[$module]); +} + /** * Loads a module's installation hooks. * @@ -183,11 +386,6 @@ function module_load_install($module) { * * @return * The name of the included file, if successful; FALSE otherwise. - * - * @todo The module_handler service has a loadInclude() method which performs - * this same task but only for enabled modules. Figure out a way to move this - * functionality entirely into the module_handler while keeping the ability to - * load the files of disabled modules. */ function module_load_include($type, $module, $name = NULL) { if (!isset($name)) { @@ -204,6 +402,15 @@ function module_load_include($type, $module, $name = NULL) { return FALSE; } +/** + * Loads an include file for each enabled module. + */ +function module_load_all_includes($type, $name = NULL) { + $modules = module_list(); + foreach ($modules as $module) { + module_load_include($type, $module, $name); + } +} /** * Enables or installs a given list of modules. @@ -287,12 +494,9 @@ function module_enable($module_list, $enable_dependencies = TRUE) { $schema_store = drupal_container()->get('keyvalue')->get('system.schema'); $module_config = config('system.module'); $disabled_config = config('system.module.disabled'); - $module_handler = drupal_container()->get('module_handler'); + $module_filenames = drupal_container()->getParameter('container.modules'); foreach ($module_list as $module) { // Only process modules that are not already enabled. - // A module is only enabled if it is configured as enabled. Custom or - // overridden module handlers might contain the module already, which means - // that it might be loaded, but not necessarily installed or enabled. $enabled = $module_config->get("enabled.$module") !== NULL; if (!$enabled) { $weight = $disabled_config->get($module); @@ -306,59 +510,21 @@ function module_enable($module_list, $enable_dependencies = TRUE) { $disabled_config ->clear($module) ->save(); - - // Prepare the new module list, sorted by weight, including filenames. - // This list is used for both the ModuleHandler and DrupalKernel. It needs - // to be kept in sync between both. A DrupalKernel reboot or rebuild will - // automatically re-instantiate a new ModuleHandler that uses the new - // module list of the kernel. However, DrupalKernel does not cause any - // modules to be loaded. - // Furthermore, the currently active (fixed) module list can be different - // from the configured list of enabled modules. For all active modules not - // contained in the configured enabled modules, we assume a weight of 0. - $current_module_filenames = $module_handler->getModuleList(); - $current_modules = array_fill_keys(array_keys($current_module_filenames), 0); - $current_modules = module_config_sort(array_merge($current_modules, $module_config->get('enabled'))); - $module_filenames = array(); - foreach ($current_modules as $name => $weight) { - if (isset($current_module_filenames[$name])) { - $filename = $current_module_filenames[$name]; - } - else { - $filename = drupal_get_filename('module', $name); - } - $module_filenames[$name] = $filename; - } - - // Update the module handler in order to load the module's code. - // This allows the module to participate in hooks and its existence to be - // discovered by other modules. - // The current ModuleHandler instance is obsolete with the kernel rebuild - // below. - $module_handler->setModuleList($module_filenames); - $module_handler->load($module); + // Load the module's code. + drupal_load('module', $module); module_load_install($module); - // Reset the the hook implementations cache. - $module_handler->resetImplementations(); - - // Flush theme info caches, since (testing) modules can implement - // hook_system_theme_info() to register additional themes. + // Refresh the module list to include it. system_list_reset(); - // Refresh the list of modules that implement bootstrap hooks. - // @see bootstrap_hooks() + module_implements_reset(); _system_update_bootstrap_status(); - + $module_filenames[$module] = drupal_get_filename('module', $module); // Update the kernel to include it. - // This reboots the kernel to register the module's bundle and its - // services in the service container. The $module_filenames argument is - // taken over as %container.modules% parameter, which is passed to a fresh - // ModuleHandler instance upon first retrieval. - // @todo install_begin_request() creates a container without a kernel. + // @todo The if statement is here because install_begin_request() creates + // a container without a kernel. It probably shouldn't. if ($kernel = drupal_container()->get('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) { - $kernel->updateModules($module_filenames, $module_filenames); + $kernel->updateModules(module_list(), $module_filenames); } - // Refresh the schema to include it. drupal_get_schema(NULL, TRUE); // Update the theme registry to include it. @@ -466,58 +632,32 @@ function module_disable($module_list, $disable_dependents = TRUE) { $module_config = config('system.module'); $disabled_config = config('system.module.disabled'); - $module_handler = drupal_container()->get('module_handler'); foreach ($module_list as $module) { - // Only process modules that are enabled. - // A module is only enabled if it is configured as enabled. Custom or - // overridden module handlers might contain the module already, which means - // that it might be loaded, but not necessarily installed or enabled. - $enabled = $module_config->get("enabled.$module") !== NULL; - if ($enabled) { + if (module_exists($module)) { module_load_install($module); module_invoke($module, 'disable'); - $disabled_config ->set($module, $module_config->get($module)) ->save(); $module_config ->clear("enabled.$module") ->save(); - - // Update the module handler to remove the module. - // The current ModuleHandler instance is obsolete with the kernel rebuild - // below. - $module_filenames = $module_handler->getModuleList(); - unset($module_filenames[$module]); - $module_handler->setModuleList($module_filenames); - - // Record the fact that it was disabled. $invoke_modules[] = $module; watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO); } } if (!empty($invoke_modules)) { - // @todo Most of the following should happen in above loop already. // Refresh the module list to exclude the disabled modules. - $module_handler->resetImplementations(); - - // Refresh the system list to exclude the disabled modules. - // @todo Only needed to rebuild theme info. - // @see system_list_reset() system_list_reset(); - + module_implements_reset(); entity_info_cache_clear(); - // 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 kernel to exclude the disabled modules. - $enabled = $module_handler->getModuleList(); - drupal_container()->get('kernel')->updateModules($enabled, $enabled); - + drupal_container()->get('kernel')->updateModules(module_list()); // Update the theme registry to remove the newly-disabled module. drupal_theme_rebuild(); } @@ -625,6 +765,200 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) * See also @link themeable the themeable group page. @endlink */ +/** + * Determines whether a module implements a hook. + * + * @param $module + * The name of the module (without the .module extension). + * @param $hook + * The name of the hook (e.g. "help" or "menu"). + * + * @return + * TRUE if the module is both installed and enabled, and the hook is + * implemented in that module. + */ +function module_hook($module, $hook) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + return TRUE; + } + // If the hook implementation does not exist, check whether it may live in an + // optional include file registered via hook_hook_info(). + $hook_info = module_hook_info(); + if (isset($hook_info[$hook]['group'])) { + module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']); + if (function_exists($function)) { + return TRUE; + } + } + return FALSE; +} + +/** + * Determines which modules are implementing a hook. + * + * @param $hook + * The name of the hook (e.g. "help" or "menu"). + * + * @return + * An array with the names of the modules which are implementing this hook. + * + * @see module_implements_write_cache() + */ +function module_implements($hook) { + // Use the advanced drupal_static() pattern, since this is called very often. + static $drupal_static_fast; + if (!isset($drupal_static_fast)) { + $drupal_static_fast['implementations'] = &drupal_static(__FUNCTION__); + } + $implementations = &$drupal_static_fast['implementations']; + + // Fetch implementations from cache. + if (empty($implementations)) { + $implementations = cache('bootstrap')->get('module_implements'); + if ($implementations === FALSE) { + $implementations = array(); + } + else { + $implementations = $implementations->data; + } + } + + if (!isset($implementations[$hook])) { + // The hook is not cached, so ensure that whether or not it has + // implementations, that the cache is updated at the end of the request. + $implementations['#write_cache'] = TRUE; + $hook_info = module_hook_info(); + $implementations[$hook] = array(); + foreach (module_list() as $module) { + $include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']); + // Since module_hook() may needlessly try to load the include file again, + // function_exists() is used directly here. + if (function_exists($module . '_' . $hook)) { + $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE; + } + } + // Allow modules to change the weight of specific implementations but avoid + // an infinite loop. + if ($hook != 'module_implements_alter') { + drupal_alter('module_implements', $implementations[$hook], $hook); + } + } + else { + foreach ($implementations[$hook] as $module => $group) { + // If this hook implementation is stored in a lazy-loaded file, so include + // that file first. + if ($group) { + module_load_include('inc', $module, "$module.$group"); + } + // It is possible that a module removed a hook implementation without the + // implementations cache being rebuilt yet, so we check whether the + // function exists on each request to avoid undefined function errors. + // Since module_hook() may needlessly try to load the include file again, + // function_exists() is used directly here. + if (!function_exists($module . '_' . $hook)) { + // Clear out the stale implementation from the cache and force a cache + // refresh to forget about no longer existing hook implementations. + unset($implementations[$hook][$module]); + $implementations['#write_cache'] = TRUE; + } + } + } + + return array_keys($implementations[$hook]); +} + +/** + * Regenerates the stored list of hook implementations. + */ +function module_implements_reset() { + // We maintain a persistent cache of hook implementations in addition to the + // static cache to avoid looping through every module and every hook on each + // request. Benchmarks show that the benefit of this caching outweighs the + // additional database hit even when using the default database caching + // backend and only a small number of modules are enabled. The cost of the + // cache('bootstrap')->get() is more or less constant and reduced further when + // non-database caching backends are used, so there will be more significant + // gains when a large number of modules are installed or hooks invoked, since + // this can quickly lead to module_hook() being called several thousand times + // per request. + drupal_static_reset('module_implements'); + cache('bootstrap')->set('module_implements', array()); + drupal_static_reset('module_hook_info'); + drupal_static_reset('drupal_alter'); + cache('bootstrap')->delete('hook_info'); +} + +/** + * Retrieves a list of hooks that are declared through hook_hook_info(). + * + * @return + * An associative array whose keys are hook names and whose values are an + * associative array containing a group name. The structure of the array + * is the same as the return value of hook_hook_info(). + * + * @see hook_hook_info() + */ +function module_hook_info() { + // When this function is indirectly invoked from bootstrap_invoke_all() prior + // to all modules being loaded, we do not want to cache an incomplete + // hook_hook_info() result, so instead return an empty array. This requires + // bootstrap hook implementations to reside in the .module file, which is + // optimal for performance anyway. + if (!module_load_all(NULL)) { + return array(); + } + $hook_info = &drupal_static(__FUNCTION__); + + if (!isset($hook_info)) { + $hook_info = array(); + $cache = cache('bootstrap')->get('hook_info'); + if ($cache === FALSE) { + // Rebuild the cache and save it. + // We can't use module_invoke_all() here or it would cause an infinite + // loop. + foreach (module_list() as $module) { + $function = $module . '_hook_info'; + if (function_exists($function)) { + $result = $function(); + if (isset($result) && is_array($result)) { + $hook_info = NestedArray::mergeDeep($hook_info, $result); + } + } + } + // We can't use drupal_alter() for the same reason as above. + foreach (module_list() as $module) { + $function = $module . '_hook_info_alter'; + if (function_exists($function)) { + $function($hook_info); + } + } + cache('bootstrap')->set('hook_info', $hook_info); + } + else { + $hook_info = $cache->data; + } + } + + return $hook_info; +} + +/** + * Writes the hook implementation cache. + * + * @see module_implements() + */ +function module_implements_write_cache() { + $implementations = &drupal_static('module_implements'); + // Check whether we need to write the cache. We do not want to cache hooks + // which are only invoked on HTTP POST requests since these do not need to be + // optimized as tightly, and not doing so keeps the cache entry smaller. + if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) { + unset($implementations['#write_cache']); + cache('bootstrap')->set('module_implements', $implementations); + } +} + /** * Invokes a hook in a particular module. * @@ -647,6 +981,39 @@ function module_invoke($module, $hook) { } } +/** + * Invokes a hook in all enabled modules that implement it. + * + * @param $hook + * The name of the hook to invoke. + * @param ... + * Arguments to pass to the hook. + * + * @return + * An array of return values of the hook implementations. If modules return + * arrays from their implementations, those are merged into one array. + */ +function module_invoke_all($hook) { + $args = func_get_args(); + // Remove $hook from the arguments. + unset($args[0]); + $return = array(); + foreach (module_implements($hook) as $module) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + $result = call_user_func_array($function, $args); + if (isset($result) && is_array($result)) { + $return = NestedArray::mergeDeep($return, $result); + } + elseif (isset($result)) { + $return[] = $result; + } + } + } + + return $return; +} + /** * @} End of "defgroup hooks". */ @@ -671,6 +1038,172 @@ function drupal_required_modules() { return $required; } +/** + * Passes alterable variables to specific hook_TYPE_alter() implementations. + * + * This dispatch function hands off the passed-in variables to type-specific + * hook_TYPE_alter() implementations in modules. It ensures a consistent + * interface for all altering operations. + * + * A maximum of 2 alterable arguments is supported. In case more arguments need + * to be passed and alterable, modules provide additional variables assigned by + * reference in the last $context argument: + * @code + * $context = array( + * 'alterable' => &$alterable, + * 'unalterable' => $unalterable, + * 'foo' => 'bar', + * ); + * drupal_alter('mymodule_data', $alterable1, $alterable2, $context); + * @endcode + * + * Note that objects are always passed by reference in PHP5. If it is absolutely + * required that no implementation alters a passed object in $context, then an + * object needs to be cloned: + * @code + * $context = array( + * 'unalterable_object' => clone $object, + * ); + * drupal_alter('mymodule_data', $data, $context); + * @endcode + * + * @param $type + * A string describing the type of the alterable $data. 'form', 'links', + * 'node_content', and so on are several examples. Alternatively can be an + * array, in which case hook_TYPE_alter() is invoked for each value in the + * array, ordered first by module, and then for each module, in the order of + * values in $type. For example, when Form API is using drupal_alter() to + * execute both hook_form_alter() and hook_form_FORM_ID_alter() + * implementations, it passes array('form', 'form_' . $form_id) for $type. + * @param $data + * The variable that will be passed to hook_TYPE_alter() implementations to be + * altered. The type of this variable depends on the value of the $type + * argument. For example, when altering a 'form', $data will be a structured + * array. When altering a 'profile', $data will be an object. + * @param $context1 + * (optional) An additional variable that is passed by reference. + * @param $context2 + * (optional) An additional variable that is passed by reference. If more + * context needs to be provided to implementations, then this should be an + * associative array as described above. + */ +function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { + // Use the advanced drupal_static() pattern, since this is called very often. + static $drupal_static_fast; + if (!isset($drupal_static_fast)) { + $drupal_static_fast['functions'] = &drupal_static(__FUNCTION__); + } + $functions = &$drupal_static_fast['functions']; + + // Most of the time, $type is passed as a string, so for performance, + // normalize it to that. When passed as an array, usually the first item in + // the array is a generic type, and additional items in the array are more + // specific variants of it, as in the case of array('form', 'form_FORM_ID'). + if (is_array($type)) { + $cid = implode(',', $type); + $extra_types = $type; + $type = array_shift($extra_types); + // Allow if statements in this function to use the faster isset() rather + // than !empty() both when $type is passed as a string, or as an array with + // one item. + if (empty($extra_types)) { + unset($extra_types); + } + } + else { + $cid = $type; + } + + // Some alter hooks are invoked many times per page request, so statically + // cache the list of functions to call, and on subsequent calls, iterate + // through them quickly. + if (!isset($functions[$cid])) { + $functions[$cid] = array(); + $hook = $type . '_alter'; + $modules = module_implements($hook); + if (!isset($extra_types)) { + // For the more common case of a single hook, we do not need to call + // function_exists(), since module_implements() returns only modules with + // implementations. + foreach ($modules as $module) { + $functions[$cid][] = $module . '_' . $hook; + } + } + else { + // For multiple hooks, we need $modules to contain every module that + // implements at least one of them. + $extra_modules = array(); + foreach ($extra_types as $extra_type) { + $extra_modules = array_merge($extra_modules, module_implements($extra_type . '_alter')); + } + // If any modules implement one of the extra hooks that do not implement + // the primary hook, we need to add them to the $modules array in their + // appropriate order. module_implements() can only return ordered + // implementations of a single hook. To get the ordered implementations + // of multiple hooks, we mimic the module_implements() logic of first + // ordering by module_list(), and then calling + // drupal_alter('module_implements'). + if (array_diff($extra_modules, $modules)) { + // Merge the arrays and order by module_list(). + $modules = array_intersect(module_list(), array_merge($modules, $extra_modules)); + // Since module_implements() already took care of loading the necessary + // include files, we can safely pass FALSE for the array values. + $implementations = array_fill_keys($modules, FALSE); + // Let modules adjust the order solely based on the primary hook. This + // ensures the same module order regardless of whether this if block + // runs. Calling drupal_alter() recursively in this way does not result + // in an infinite loop, because this call is for a single $type, so we + // won't end up in this code block again. + drupal_alter('module_implements', $implementations, $hook); + $modules = array_keys($implementations); + } + foreach ($modules as $module) { + // Since $modules is a merged array, for any given module, we do not + // know whether it has any particular implementation, so we need a + // function_exists(). + $function = $module . '_' . $hook; + if (function_exists($function)) { + $functions[$cid][] = $function; + } + foreach ($extra_types as $extra_type) { + $function = $module . '_' . $extra_type . '_alter'; + if (function_exists($function)) { + $functions[$cid][] = $function; + } + } + } + } + // Allow the theme to alter variables after the theme system has been + // initialized. + global $theme, $base_theme_info; + if (isset($theme)) { + $theme_keys = array(); + foreach ($base_theme_info as $base) { + $theme_keys[] = $base->name; + } + $theme_keys[] = $theme; + foreach ($theme_keys as $theme_key) { + $function = $theme_key . '_' . $hook; + if (function_exists($function)) { + $functions[$cid][] = $function; + } + if (isset($extra_types)) { + foreach ($extra_types as $extra_type) { + $function = $theme_key . '_' . $extra_type . '_alter'; + if (function_exists($function)) { + $functions[$cid][] = $function; + } + } + } + } + } + } + + foreach ($functions[$cid] as $function) { + $function($data, $context1, $context2); + } +} + /** * Sets weight of a particular module. * @@ -689,19 +1222,6 @@ function module_set_weight($module, $weight) { ->set("enabled.$module", $weight) ->set('enabled', module_config_sort($module_config->get('enabled'))) ->save(); - - // Prepare the new module list, sorted by weight, including filenames. - // @see module_enable() - $module_handler = drupal_container()->get('module_handler'); - $current_module_filenames = $module_handler->getModuleList(); - $current_modules = array_fill_keys(array_keys($current_module_filenames), 0); - $current_modules = module_config_sort(array_merge($current_modules, $module_config->get('enabled'))); - $module_filenames = array(); - foreach ($current_modules as $name => $weight) { - $module_filenames[$name] = $current_module_filenames[$name]; - } - // Update the module list in the extension handler. - $module_handler->setModuleList($module_filenames); return; } $disabled_config = config('system.module.disabled'); diff --git a/core/includes/schema.inc b/core/includes/schema.inc index e59992370b2c404e6a6bde6ed4eaeb66ca9f7f74..b37014501f76e3383c7c496e55dee806cfca3996 100644 --- a/core/includes/schema.inc +++ b/core/includes/schema.inc @@ -77,7 +77,16 @@ function drupal_get_complete_schema($rebuild = FALSE) { else { $schema = array(); // Load the .install files to get hook_schema. - drupal_container()->get('module_handler')->loadAllIncludes('install'); + // On some databases this function may be called before bootstrap has + // been completed, so we force the functions we need to load just in case. + if (function_exists('module_load_all_includes')) { + // This function can be called very early in the bootstrap process, so + // we force the system_list() static cache to be refreshed to ensure + // that it contains the complete list of modules before we go on to call + // module_load_all_includes(). + system_list_reset(); + module_load_all_includes('install'); + } require_once DRUPAL_ROOT . '/core/includes/common.inc'; // Invoke hook_schema for all modules. @@ -121,7 +130,8 @@ function drupal_get_schema_versions($module) { $updates = &drupal_static(__FUNCTION__, NULL); if (!isset($updates[$module])) { $updates = array(); - foreach (drupal_container()->get('module_handler')->getModuleList() as $loaded_module => $filename) { + + foreach (module_list() as $loaded_module) { $updates[$loaded_module] = array(); } @@ -331,9 +341,7 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU * An array of fields. */ function drupal_schema_fields_sql($table, $prefix = NULL) { - if (!$schema = drupal_get_schema($table)) { - return array(); - } + $schema = drupal_get_schema($table); $fields = array_keys($schema['fields']); if ($prefix) { $columns = array(); diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 5dd028b914e3b69cec87b79b26832c8f37d53dd7..bab2af5228d525f47f2e798687c605bd3ad0f791 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -368,14 +368,14 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL, $registry = _theme_build_registry($theme, $base_theme, $theme_engine); // Only persist this registry if all modules are loaded. This assures a // complete set of theme hooks. - if (drupal_container()->get('module_handler')->isLoaded()) { + if (module_load_all(NULL)) { _theme_save_registry($theme, $registry); } } return $registry; } else { - return new ThemeRegistry('theme_registry:runtime:' . $theme->name, 'cache', array('theme_registry' => TRUE), drupal_container()->get('module_handler')->isLoaded()); + return new ThemeRegistry('theme_registry:runtime:' . $theme->name, 'cache', array('theme_registry' => TRUE)); } } @@ -441,6 +441,7 @@ function drupal_theme_rebuild() { * themes/bartik. * * @see theme() + * @see _theme_process_registry() * @see hook_theme() * @see list_themes() */ @@ -547,7 +548,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) { // Add all modules so they can intervene with their own variable // processors. This allows them to provide variable processors even // if they are not the owner of the current hook. - $prefixes = array_merge($prefixes, array_keys(drupal_container()->get('module_handler')->getModuleList())); + $prefixes += module_list(); } elseif ($type == 'theme_engine' || $type == 'base_theme_engine') { // Theme engines get an extra set that come before the normally @@ -643,7 +644,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) { _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); } // Only cache this registry if all modules are loaded. - if (drupal_container()->get('module_handler')->isLoaded()) { + if (module_load_all(NULL)) { cache()->set("theme_registry:build:modules", $cache, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); } } @@ -958,7 +959,7 @@ function theme($hook, $variables = array()) { // If called before all modules are loaded, we do not necessarily have a full // theme registry to work with, and therefore cannot process the theme // request properly. See also _theme_load_registry(). - if (!drupal_container()->get('module_handler')->isLoaded() && !defined('MAINTENANCE_MODE')) { + if (!module_load_all(NULL) && !defined('MAINTENANCE_MODE')) { throw new Exception(t('theme() may not be called until all modules are loaded.')); } diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index 0b426e210a58d65c01bee1eecd775365ae82c24e..ba8866133fd446e0d66d0d4efa558468dd3e9d56 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -55,10 +55,9 @@ function _drupal_maintenance_theme() { // Ensure that system.module is loaded. if (!function_exists('_system_rebuild_theme_data')) { - $module_list['system'] = 'core/modules/system/system.module'; - $module_handler = drupal_container()->get('module_handler'); - $module_handler->setModuleList($module_list); - $module_handler->load('system'); + $module_list['system']['filename'] = 'core/modules/system/system.module'; + module_list(NULL, $module_list); + drupal_load('module', 'system'); } $themes = list_themes(); diff --git a/core/includes/update.inc b/core/includes/update.inc index 45cad2284aa00d0bb72431eaaf1aabf8166363fd..cdcae638258abb1bec4b3c0bca919c9cb50ad234 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -91,7 +91,7 @@ function update_prepare_d8_bootstrap() { include_once DRUPAL_ROOT . '/core/includes/install.inc'; include_once DRUPAL_ROOT . '/core/includes/schema.inc'; // Bootstrap to configuration. - drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL); + drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); // Check whether settings.php needs to be rewritten. $settings_exist = !empty($GLOBALS['config_directories']); @@ -125,9 +125,9 @@ function update_prepare_d8_bootstrap() { include_once DRUPAL_ROOT . '/core/includes/module.inc'; include_once DRUPAL_ROOT . '/core/includes/cache.inc'; - $module_handler = drupal_container()->get('module_handler'); - $module_handler->setModuleList(array('system' => 'core/modules/system/system.module')); - $module_handler->load('system'); + $module_list['system']['filename'] = 'core/modules/system/system.module'; + module_list(NULL, $module_list); + require_once DRUPAL_ROOT . '/' . $module_list['system']['filename']; // 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 @@ -353,8 +353,8 @@ function update_prepare_d8_bootstrap() { // Populate a fixed module list (again, why did it get lost?) to avoid // errors due to the drupal_alter() in _system_rebuild_module_data(). - $module_list['system'] = 'core/modules/system/system.module'; - drupal_container()->get('module_handler')->setModuleList($module_list); + $module_list['system']['filename'] = 'core/modules/system/system.module'; + module_list(NULL, $module_list); $module_data = _system_rebuild_module_data(); // Migrate each extension into configuration, varying by the extension's @@ -378,13 +378,7 @@ function update_prepare_d8_bootstrap() { } $schema_store->set($record->name, $record->schema_version); } - $sorted_modules = module_config_sort($module_config->get('enabled')); - $module_config->set('enabled', $sorted_modules)->save(); - $sorted_with_filenames = array(); - foreach (array_keys($sorted_modules) as $m) { - $sorted_with_filenames[$m] = drupal_get_filename('module', $m); - } - drupal_container()->get('module_handler')->setModuleList($sorted_with_filenames); + $module_config->set('enabled', module_config_sort($module_config->get('enabled')))->save(); $disabled_modules->save(); $theme_config->save(); $disabled_themes->save(); @@ -394,6 +388,8 @@ function update_prepare_d8_bootstrap() { 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')) { diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index e70b1fc62c6b26a2f1d1274fe2d9e3d0bff40c91..207670758dd7cc53293c9083991456f720dda9fc 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -77,12 +77,6 @@ public function build(ContainerBuilder $container) { ->setFactoryClass('Drupal\Component\Utility\Settings') ->setFactoryMethod('getSingleton'); - // Register the State k/v store as a service. - $container->register('state', 'Drupal\Core\KeyValueStore\KeyValueStoreInterface') - ->setFactoryService(new Reference('keyvalue')) - ->setFactoryMethod('get') - ->addArgument('state'); - // Register the Queue factory. $container ->register('queue', 'Drupal\Core\Queue\QueueFactory') @@ -120,20 +114,6 @@ public function build(ContainerBuilder $container) { ->addArgument(new Reference('service_container')); $container->register('controller_resolver', 'Drupal\Core\ControllerResolver') ->addArgument(new Reference('service_container')); - - $container - ->register('cache.cache', 'Drupal\Core\Cache\CacheBackendInterface') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') - ->setFactoryMethod('get') - ->addArgument('cache'); - $container - ->register('cache.bootstrap', 'Drupal\Core\Cache\CacheBackendInterface') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') - ->setFactoryMethod('get') - ->addArgument('bootstrap'); - - $this->registerModuleHandler($container); - $container->register('http_kernel', 'Drupal\Core\HttpKernel') ->addArgument(new Reference('event_dispatcher')) ->addArgument(new Reference('service_container')) @@ -164,8 +144,7 @@ public function build(ContainerBuilder $container) { $container->register('router.builder', 'Drupal\Core\Routing\RouteBuilder') ->addArgument(new Reference('router.dumper')) ->addArgument(new Reference('lock')) - ->addArgument(new Reference('event_dispatcher')) - ->addArgument(new Reference('module_handler')); + ->addArgument(new Reference('event_dispatcher')); $container ->register('cache.path', 'Drupal\Core\Cache\CacheBackendInterface') @@ -230,7 +209,6 @@ public function build(ContainerBuilder $container) { ->setScope('request') ->addTag('event_subscriber'); $container->register('request_close_subscriber', 'Drupal\Core\EventSubscriber\RequestCloseSubscriber') - ->addArgument(new Reference('module_handler')) ->addTag('event_subscriber'); $container->register('config_global_override_subscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber') ->addTag('event_subscriber'); @@ -269,25 +247,6 @@ public function build(ContainerBuilder $container) { $container->addCompilerPass(new RegisterAccessChecksPass()); } - /** - * Registers the module handler. - */ - protected function registerModuleHandler(ContainerBuilder $container) { - // The ModuleHandler manages enabled modules and provides the ability to - // invoke hooks in all enabled modules. - if ($container->getParameter('kernel.environment') == 'install') { - // During installation we use the non-cached version. - $container->register('module_handler', 'Drupal\Core\Extension\ModuleHandler') - ->addArgument('%container.modules%'); - } - else { - $container->register('module_handler', 'Drupal\Core\Extension\CachedModuleHandler') - ->addArgument('%container.modules%') - ->addArgument(new Reference('state')) - ->addArgument(new Reference('cache.bootstrap')); - } - } - /** * Registers the various services for the routing system. * diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index d56f5037c86df05925be8a05f863b2c01821c4d3..ffa5ef4a3938f20a524093417003737a3383f16c 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -223,9 +223,6 @@ protected function moduleData($module) { /** * Implements Drupal\Core\DrupalKernelInterface::updateModules(). - * - * @todo Remove obsolete $module_list parameter. Only $module_filenames is - * needed. */ public function updateModules(array $module_list, array $module_filenames = array()) { $this->newModuleList = $module_list; diff --git a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php index eb295bdb8261f98d04bf5cc4390546fdd10e6a10..8d5f87a6ac46e0d06353ec6932998550adb5bdf1 100644 --- a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php @@ -7,8 +7,6 @@ namespace Drupal\Core\EventSubscriber; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Extension\CachedModuleHandlerInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\PostResponseEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -18,18 +16,6 @@ */ class RequestCloseSubscriber implements EventSubscriberInterface { - /** - * @var \Drupal\Core\Extension\ModuleHandlerInterface - */ - protected $moduleHandler; - - /** - * Constructor. - */ - function __construct(ModuleHandlerInterface $module_handler) { - $this->moduleHandler = $module_handler; - } - /** * Performs end of request tasks. * @@ -42,15 +28,8 @@ function __construct(ModuleHandlerInterface $module_handler) { * The Event to process. */ public function onTerminate(PostResponseEvent $event) { - $this->moduleHandler->invokeAll('exit'); - $request_method = $event->getRequest()->getMethod(); - // Check whether we need to write the module implementations cache. We do - // not want to cache hooks which are only invoked on HTTP POST requests - // since these do not need to be optimized as tightly, and not doing so - // keeps the cache entry smaller. - if (($request_method == 'GET' || $request_method == 'HEAD') && $this->moduleHandler instanceof CachedModuleHandlerInterface) { - $this->moduleHandler->writeCache(); - } + module_invoke_all('exit'); + module_implements_write_cache(); system_run_automated_cron(); } diff --git a/core/lib/Drupal/Core/Extension/CachedModuleHandler.php b/core/lib/Drupal/Core/Extension/CachedModuleHandler.php deleted file mode 100644 index a3f3eac4eeb22609e4b7b1a04a1c8a9e2d674644..0000000000000000000000000000000000000000 --- a/core/lib/Drupal/Core/Extension/CachedModuleHandler.php +++ /dev/null @@ -1,167 +0,0 @@ -state = $state; - $this->bootstrapCache = $bootstrap_cache; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::getBootstrapModules(). - */ - public function getBootstrapModules() { - if (isset($this->bootstrapModules)) { - return $this->bootstrapModules; - } - if ($cached = $this->bootstrapCache->get('bootstrap_modules')) { - $bootstrap_list = $cached->data; - } - else { - $bootstrap_list = $this->state->get('system.module.bootstrap') ?: array(); - $this->bootstrapCache->set('bootstrap_modules', $bootstrap_list); - } - $this->bootstrapModules = array_keys($bootstrap_list); - return $this->bootstrapModules; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::resetImplementations(). - */ - public function resetImplementations() { - // We maintain a persistent cache of hook implementations in addition to the - // static cache to avoid looping through every module and every hook on each - // request. Benchmarks show that the benefit of this caching outweighs the - // additional database hit even when using the default database caching - // backend and only a small number of modules are enabled. The cost of the - // $this->bootstrapCache->get() is more or less constant and reduced further when - // non-database caching backends are used, so there will be more significant - // gains when a large number of modules are installed or hooks invoked, since - // this can quickly lead to module_hook() being called several thousand times - // per request. - parent::resetImplementations(); - $this->bootstrapCache->set('module_implements', array()); - $this->bootstrapCache->delete('hook_info'); - } - - /** - * Implements \Drupal\Core\Extension\CachedModuleHandlerInterface::writeCache(). - */ - public function writeCache() { - if ($this->cacheNeedsWriting) { - $this->bootstrapCache->set('module_implements', $this->implementations); - $this->cacheNeedsWriting = FALSE; - } - } - - /** - * Overrides \Drupal\Core\Extension\ModuleHandler::getImplementationInfo(). - */ - protected function getImplementationInfo($hook) { - if (!isset($this->implementations)) { - $this->implementations = $this->getCachedImplementationInfo(); - } - if (!isset($this->implementations[$hook])) { - // The hook is not cached, so ensure that whether or not it has - // implementations, the cache is updated at the end of the request. - $this->cacheNeedsWriting = TRUE; - $this->implementations[$hook] = parent::getImplementationInfo($hook); - } - else { - foreach ($this->implementations[$hook] as $module => $group) { - // If this hook implementation is stored in a lazy-loaded file, include - // that file first. - if ($group) { - $this->loadInclude($module, 'inc', "$module.$group"); - } - // It is possible that a module removed a hook implementation without the - // implementations cache being rebuilt yet, so we check whether the - // function exists on each request to avoid undefined function errors. - // Since module_hook() may needlessly try to load the include file again, - // function_exists() is used directly here. - if (!function_exists($module . '_' . $hook)) { - // Clear out the stale implementation from the cache and force a cache - // refresh to forget about no longer existing hook implementations. - unset($this->implementations[$hook][$module]); - $this->cacheNeedsWriting = TRUE; - } - } - } - return $this->implementations[$hook]; - } - - /** - * Overrides \Drupal\Core\Extension\ModuleHandler::getHookInfo(). - */ - protected function getHookInfo() { - // When this function is indirectly invoked from bootstrap_invoke_all() prior - // to all modules being loaded, we do not want to cache an incomplete - // hook_hookInfo() result, so instead return an empty array. This requires - // bootstrap hook implementations to reside in the .module file, which is - // optimal for performance anyway. - if (!$this->loaded) { - return array(); - } - if (!isset($this->hookInfo)) { - if ($cache = $this->bootstrapCache->get('hook_info')) { - $this->hookInfo = $cache->data; - } - else { - $this->hookInfo = parent::getHookInfo(); - $this->bootstrapCache->set('hook_info', $this->hookInfo); - } - } - return $this->hookInfo; - } - - /** - * Retrieves hook implementation info from the cache. - */ - protected function getCachedImplementationInfo() { - if ($cache = $this->bootstrapCache->get('module_implements')) { - return $cache->data; - } - else { - return array(); - } - } - -} diff --git a/core/lib/Drupal/Core/Extension/CachedModuleHandlerInterface.php b/core/lib/Drupal/Core/Extension/CachedModuleHandlerInterface.php deleted file mode 100644 index cca18dc905ae4a45ccc4e3c645fbeed68e21a7fd..0000000000000000000000000000000000000000 --- a/core/lib/Drupal/Core/Extension/CachedModuleHandlerInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -moduleList = $module_list; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::load(). - */ - public function load($name) { - if (isset($this->loadedFiles[$name])) { - return TRUE; - } - - if (isset($this->moduleList[$name])) { - $filename = $this->moduleList[$name]; - include_once DRUPAL_ROOT . '/' . $filename; - $this->loadedFiles[$name] = TRUE; - return TRUE; - } - return FALSE; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::loadAll(). - */ - public function loadAll() { - if (!$this->loaded) { - foreach ($this->moduleList as $module => $filename) { - $this->load($module); - } - $this->loaded = TRUE; - } - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::reload(). - */ - public function reload() { - $this->loaded = FALSE; - $this->loadAll(); - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::loadBootstrapModules(). - */ - public function loadBootstrapModules() { - if (!$this->loaded) { - foreach ($this->getBootstrapModules() as $module) { - $this->load($module); - } - } - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::isLoaded(). - */ - public function isLoaded() { - return $this->loaded; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::getModuleList(). - */ - public function getModuleList() { - return $this->moduleList; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::setModuleList(). - */ - public function setModuleList(array $module_list = array()) { - $this->moduleList = $module_list; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::getBootstrapModules(). - */ - public function getBootstrapModules() { - // The basic module handler does not know anything about how to retrieve a - // list of bootstrap modules. - return array(); - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::buildModuleDependencies(). - */ - public function buildModuleDependencies(array $modules) { - foreach ($modules as $name => $module) { - $graph[$module->name]['edges'] = array(); - if (isset($module->info['dependencies']) && is_array($module->info['dependencies'])) { - foreach ($module->info['dependencies'] as $dependency) { - $dependency_data = $this->parseDependency($dependency); - $graph[$module->name]['edges'][$dependency_data['name']] = $dependency_data; - } - } - } - $graph_object = new Graph($graph); - $graph = $graph_object->searchAndSort(); - foreach ($graph as $module_name => $data) { - $modules[$module_name]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array(); - $modules[$module_name]->requires = isset($data['paths']) ? $data['paths'] : array(); - $modules[$module_name]->sort = $data['weight']; - } - return $modules; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::moduleExists(). - */ - public function moduleExists($module) { - return isset($this->moduleList[$module]); - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::loadAllIncludes(). - */ - public function loadAllIncludes($type, $name = NULL) { - foreach ($this->moduleList as $module => $filename) { - $this->loadInclude($module, $type, $name); - } - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::loadInclude(). - */ - public function loadInclude($module, $type, $name = NULL) { - if ($type == 'install') { - // Make sure the installation API is available - include_once DRUPAL_ROOT . '/core/includes/install.inc'; - } - - $name = $name ?: $module; - $file = DRUPAL_ROOT . '/' . dirname($this->moduleList[$module]) . "/$name.$type"; - if (is_file($file)) { - require_once $file; - return $file; - } - - return FALSE; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::getImplementations(). - */ - public function getImplementations($hook) { - $implementations = $this->getImplementationInfo($hook); - return array_keys($implementations); - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::resetImplementations(). - */ - public function resetImplementations() { - $this->implementations = NULL; - $this->hookInfo = NULL; - $this->alterFunctions = NULL; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::implementsHook(). - */ - public function implementsHook($module, $hook) { - $function = $module . '_' . $hook; - if (function_exists($function)) { - return TRUE; - } - // If the hook implementation does not exist, check whether it lives in an - // optional include file registered via hook_hook_info(). - $hook_info = $this->getHookInfo(); - if (isset($hook_info[$hook]['group'])) { - $this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']); - if (function_exists($function)) { - return TRUE; - } - } - return FALSE; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::invokeAll(). - */ - public function invokeAll($hook, $args = array()) { - $return = array(); - $implementations = $this->getImplementations($hook); - foreach ($implementations as $module) { - $function = $module . '_' . $hook; - if (function_exists($function)) { - $result = call_user_func_array($function, $args); - if (isset($result) && is_array($result)) { - $return = NestedArray::mergeDeep($return, $result); - } - elseif (isset($result)) { - $return[] = $result; - } - } - } - - return $return; - } - - /** - * Implements \Drupal\Core\Extension\ModuleHandlerInterface::alter(). - */ - public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { - // Most of the time, $type is passed as a string, so for performance, - // normalize it to that. When passed as an array, usually the first item in - // the array is a generic type, and additional items in the array are more - // specific variants of it, as in the case of array('form', 'form_FORM_ID'). - if (is_array($type)) { - $cid = implode(',', $type); - $extra_types = $type; - $type = array_shift($extra_types); - // Allow if statements in this function to use the faster isset() rather - // than !empty() both when $type is passed as a string, or as an array with - // one item. - if (empty($extra_types)) { - unset($extra_types); - } - } - else { - $cid = $type; - } - - // Some alter hooks are invoked many times per page request, so store the - // list of functions to call, and on subsequent calls, iterate through them - // quickly. - if (!isset($this->alterFunctions[$cid])) { - $this->alterFunctions[$cid] = array(); - $hook = $type . '_alter'; - $modules = $this->getImplementations($hook); - if (!isset($extra_types)) { - // For the more common case of a single hook, we do not need to call - // function_exists(), since $this->getImplementations() returns only modules with - // implementations. - foreach ($modules as $module) { - $this->alterFunctions[$cid][] = $module . '_' . $hook; - } - } - else { - // For multiple hooks, we need $modules to contain every module that - // implements at least one of them. - $extra_modules = array(); - foreach ($extra_types as $extra_type) { - $extra_modules = array_merge($extra_modules, $this->getImplementations($extra_type . '_alter')); - } - // If any modules implement one of the extra hooks that do not implement - // the primary hook, we need to add them to the $modules array in their - // appropriate order. $this->getImplementations() can only return ordered - // implementations of a single hook. To get the ordered implementations - // of multiple hooks, we mimic the $this->getImplementations() logic of first - // ordering by $this->getModuleList(), and then calling - // $this->alter('module_implements'). - if (array_diff($extra_modules, $modules)) { - // Merge the arrays and order by getModuleList(). - $modules = array_intersect(array_keys($this->moduleList), array_merge($modules, $extra_modules)); - // Since $this->getImplementations() already took care of loading the necessary - // include files, we can safely pass FALSE for the array values. - $implementations = array_fill_keys($modules, FALSE); - // Let modules adjust the order solely based on the primary hook. This - // ensures the same module order regardless of whether this if block - // runs. Calling $this->alter() recursively in this way does not result - // in an infinite loop, because this call is for a single $type, so we - // won't end up in this code block again. - $this->alter('module_implements', $implementations, $hook); - $modules = array_keys($implementations); - } - foreach ($modules as $module) { - // Since $modules is a merged array, for any given module, we do not - // know whether it has any particular implementation, so we need a - // function_exists(). - $function = $module . '_' . $hook; - if (function_exists($function)) { - $this->alterFunctions[$cid][] = $function; - } - foreach ($extra_types as $extra_type) { - $function = $module . '_' . $extra_type . '_alter'; - if (function_exists($function)) { - $this->alterFunctions[$cid][] = $function; - } - } - } - } - // Allow the theme to alter variables after the theme system has been - // initialized. - global $theme, $base_theme_info; - if (isset($theme)) { - $theme_keys = array(); - foreach ($base_theme_info as $base) { - $theme_keys[] = $base->name; - } - $theme_keys[] = $theme; - foreach ($theme_keys as $theme_key) { - $function = $theme_key . '_' . $hook; - if (function_exists($function)) { - $this->alterFunctions[$cid][] = $function; - } - if (isset($extra_types)) { - foreach ($extra_types as $extra_type) { - $function = $theme_key . '_' . $extra_type . '_alter'; - if (function_exists($function)) { - $this->alterFunctions[$cid][] = $function; - } - } - } - } - } - } - - foreach ($this->alterFunctions[$cid] as $function) { - $function($data, $context1, $context2); - } - } - - /** - * Provides information about modules' implementations of a hook. - * - * @param string $hook - * The name of the hook (e.g. "help" or "menu"). - * - * @return array - * An array whose keys are the names of the modules which are implementing - * this hook and whose values are either an array of information from - * hook_hook_info() or FALSE if the implementation is in the module file. - */ - protected function getImplementationInfo($hook) { - if (isset($this->implementations[$hook])) { - return $this->implementations[$hook]; - } - $this->implementations[$hook] = array(); - $hook_info = $this->getHookInfo(); - foreach ($this->moduleList as $module => $filename) { - $include_file = isset($hook_info[$hook]['group']) && $this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']); - // Since $this->hookImplements() may needlessly try to load the include - // file again, function_exists() is used directly here. - if (function_exists($module . '_' . $hook)) { - $this->implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE; - } - } - // Allow modules to change the weight of specific implementations but avoid - // an infinite loop. - if ($hook != 'module_implements_alter') { - $this->alter('module_implements', $this->implementations[$hook], $hook); - } - return $this->implementations[$hook]; - } - - /** - * Retrieves a list of hooks that are declared through hook_hook_info(). - * - * @return - * An associative array whose keys are hook names and whose values are an - * associative array containing a group name. The structure of the array - * is the same as the return value of hook_hook_info(). - * - * @see hook_hook_info() - */ - protected function getHookInfo() { - if ($this->hookInfo) { - return $this->hookInfo; - } - $this->hookInfo = array(); - // We can't use $this->invokeAll() here or it would cause an infinite - // loop. - foreach ($this->moduleList as $module => $filename) { - $function = $module . '_hook_info'; - if (function_exists($function)) { - $result = $function(); - if (isset($result) && is_array($result)) { - $this->hookInfo = NestedArray::mergeDeep($this->hookInfo, $result); - } - } - } - // We can't use $this->alter() for the same reason as above. - foreach ($this->moduleList as $module => $filename) { - $function = $module . '_hook_info_alter'; - if (function_exists($function)) { - $function($this->hookInfo); - } - } - return $this->hookInfo; - } - - /** - * Parses a dependency for comparison by drupal_check_incompatibility(). - * - * @param $dependency - * A dependency string, for example 'foo (>=8.x-4.5-beta5, 3.x)'. - * - * @return - * An associative array with three keys: - * - 'name' includes the name of the thing to depend on (e.g. 'foo'). - * - 'original_version' contains the original version string (which can be - * used in the UI for reporting incompatibilities). - * - 'versions' is a list of associative arrays, each containing the keys - * 'op' and 'version'. 'op' can be one of: '=', '==', '!=', '<>', '<', - * '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'. - * Callers should pass this structure to drupal_check_incompatibility(). - * - * @see drupal_check_incompatibility() - */ - protected function parseDependency($dependency) { - // We use named subpatterns and support every op that version_compare - // supports. Also, op is optional and defaults to equals. - $p_op = '(?P!=|==|=|<|<=|>|>=|<>)?'; - // Core version is always optional: 8.x-2.x and 2.x is treated the same. - $p_core = '(?:' . preg_quote(DRUPAL_CORE_COMPATIBILITY) . '-)?'; - $p_major = '(?P\d+)'; - // By setting the minor version to x, branches can be matched. - $p_minor = '(?P(?:\d+|x)(?:-[A-Za-z]+\d+)?)'; - $value = array(); - $parts = explode('(', $dependency, 2); - $value['name'] = trim($parts[0]); - if (isset($parts[1])) { - $value['original_version'] = ' (' . $parts[1]; - foreach (explode(',', $parts[1]) as $version) { - if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) { - $op = !empty($matches['operation']) ? $matches['operation'] : '='; - if ($matches['minor'] == 'x') { - // Drupal considers "2.x" to mean any version that begins with - // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(), - // on the other hand, treats "x" as a string; so to - // version_compare(), "2.x" is considered less than 2.0. This - // means that >=2.x and <2.x are handled by version_compare() - // as we need, but > and <= are not. - if ($op == '>' || $op == '<=') { - $matches['major']++; - } - // Equivalence can be checked by adding two restrictions. - if ($op == '=' || $op == '==') { - $value['versions'][] = array('op' => '<', 'version' => ($matches['major'] + 1) . '.x'); - $op = '>='; - } - } - $value['versions'][] = array('op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']); - } - } - } - return $value; - } -} diff --git a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php deleted file mode 100644 index 7cb84186aafeaf5d58763bfe117248ef9d0eda59..0000000000000000000000000000000000000000 --- a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php +++ /dev/null @@ -1,238 +0,0 @@ -loadInclude('node', 'inc', 'node.admin'); - * // Load content_types.inc from the node module. - * $this->loadInclude('node', 'inc', ''content_types'); - * @endcode - * - * @param string $module - * The module to which the include file belongs. - * @param string $type - * The include file's type (file extension). - * @param string $name - * (optional) The base file name (without the $type extension). If omitted, - * $module is used; i.e., resulting in "$module.$type" by default. - * - * @return string|false - * The name of the included file, if successful; FALSE otherwise. - */ - public function loadInclude($module, $type, $name = NULL); - - /** - * Determines which modules are implementing a hook. - * - * @param string $hook - * The name of the hook (e.g. "help" or "menu"). - * - * @return array - * An array with the names of the modules which are implementing this hook. - */ - public function getImplementations($hook); - - /** - * Resets the cached list of hook implementations. - */ - public function resetImplementations(); - - /** - * Returns whether a given module implements a given hook. - * - * @param string $module - * The name of the module (without the .module extension). - * @param string $hook - * The name of the hook (e.g. "help" or "menu"). - * - * @return bool - * TRUE if the module is both installed and enabled, and the hook is - * implemented in that module. - */ - public function implementsHook($module, $hook); - - /** - * Invokes a hook in all enabled modules that implement it. - * - * @param string $hook - * The name of the hook to invoke. - * @param ... - * Arguments to pass to the hook. - * - * @return array - * An array of return values of the hook implementations. If modules return - * arrays from their implementations, those are merged into one array. - */ - public function invokeAll($hook, $args = array()); - - /** - * Passes alterable variables to specific hook_TYPE_alter() implementations. - * - * This dispatch function hands off the passed-in variables to type-specific - * hook_TYPE_alter() implementations in modules. It ensures a consistent - * interface for all altering operations. - * - * A maximum of 2 alterable arguments is supported. In case more arguments need - * to be passed and alterable, modules provide additional variables assigned by - * reference in the last $context argument: - * @code - * $context = array( - * 'alterable' => &$alterable, - * 'unalterable' => $unalterable, - * 'foo' => 'bar', - * ); - * $this->alter('mymodule_data', $alterable1, $alterable2, $context); - * @endcode - * - * Note that objects are always passed by reference in PHP5. If it is absolutely - * required that no implementation alters a passed object in $context, then an - * object needs to be cloned: - * @code - * $context = array( - * 'unalterable_object' => clone $object, - * ); - * $this->alter('mymodule_data', $data, $context); - * @endcode - * - * @param string|array $type - * A string describing the type of the alterable $data. 'form', 'links', - * 'node_content', and so on are several examples. Alternatively can be an - * array, in which case hook_TYPE_alter() is invoked for each value in the - * array, ordered first by module, and then for each module, in the order of - * values in $type. For example, when Form API is using $this->alter() to - * execute both hook_form_alter() and hook_form_FORM_ID_alter() - * implementations, it passes array('form', 'form_' . $form_id) for $type. - * @param mixed $data - * The variable that will be passed to hook_TYPE_alter() implementations to be - * altered. The type of this variable depends on the value of the $type - * argument. For example, when altering a 'form', $data will be a structured - * array. When altering a 'profile', $data will be an object. - * @param mixed $context1 - * (optional) An additional variable that is passed by reference. - * @param mixed $context2 - * (optional) An additional variable that is passed by reference. If more - * context needs to be provided to implementations, then this should be an - * associative array as described above. - */ - public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL); - -} diff --git a/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php index 232e47e45c6bfce19855a2d1bbe84e1d974f9e09..6f7a86edaf2ac0ac762b775ba2c9b957635d898b 100644 --- a/core/lib/Drupal/Core/Routing/RouteBuilder.php +++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php @@ -13,7 +13,6 @@ use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; -use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Lock\LockBackendInterface; /** @@ -45,13 +44,6 @@ class RouteBuilder { */ protected $dispatcher; - /** - * The extension handler for retieving the list of enabled modules. - * - * @var \Drupal\Core\Extension\ModuleHandlerInterface - */ - protected $moduleHandler; - /** * Construcs the RouteBuilder using the passed MatcherDumperInterface. * @@ -62,11 +54,10 @@ class RouteBuilder { * @param \Symfony\Component\EventDispatcherEventDispatcherInterface * The event dispatcher to notify of routes. */ - public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler) { + public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher) { $this->dumper = $dumper; $this->lock = $lock; $this->dispatcher = $dispatcher; - $this->moduleHandler = $module_handler; } /** @@ -85,9 +76,11 @@ public function rebuild() { // We need to manually call each module so that we can know which module // a given item came from. - foreach ($this->moduleHandler->getModuleList() as $module => $filename) { + // @todo Use an injected Extension service rather than module_list(): + // http://drupal.org/node/1331486. + foreach (module_list() as $module) { $collection = new RouteCollection(); - $routing_file = DRUPAL_ROOT . '/' . dirname($filename) . '/' . $module . '.routing.yml'; + $routing_file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . '/' . $module . '.routing.yml'; if (file_exists($routing_file)) { $routes = $parser->parse(file_get_contents($routing_file)); if (!empty($routes)) { diff --git a/core/lib/Drupal/Core/Utility/ThemeRegistry.php b/core/lib/Drupal/Core/Utility/ThemeRegistry.php index eb2dd80566bb5a49bf109c9b77a981c055b20c8e..bc9691caf655c8918c88ad1409b2e050634048d0 100644 --- a/core/lib/Drupal/Core/Utility/ThemeRegistry.php +++ b/core/lib/Drupal/Core/Utility/ThemeRegistry.php @@ -42,14 +42,12 @@ class ThemeRegistry extends CacheArray { * The bin to cache the array. * @param array $tags * (optional) The tags to specify for the cache item. - * @param bool $modules_loaded - * Whether all modules have already been loaded. */ - function __construct($cid, $bin, $tags, $modules_loaded = FALSE) { + function __construct($cid, $bin, $tags) { $this->cid = $cid; $this->bin = $bin; $this->tags = $tags; - $this->persistable = $modules_loaded && $_SERVER['REQUEST_METHOD'] == 'GET'; + $this->persistable = module_load_all(NULL) && $_SERVER['REQUEST_METHOD'] == 'GET'; $data = array(); if ($this->persistable && $cached = cache($this->bin)->get($this->cid)) { diff --git a/core/modules/breakpoint/breakpoint.install b/core/modules/breakpoint/breakpoint.install index cba7b1b5af159be6777956829309b28f022c5b73..0e6bc30410d6173715fc9166e683d13177a24952 100644 --- a/core/modules/breakpoint/breakpoint.install +++ b/core/modules/breakpoint/breakpoint.install @@ -18,5 +18,6 @@ function breakpoint_enable() { _breakpoint_theme_enabled(array_keys($themes)); // Import breakpoints from modules. - _breakpoint_modules_enabled(array_keys(drupal_container()->get('module_handler')->getModuleList())); + $modules = module_list(); + _breakpoint_modules_enabled(array_keys($modules)); } diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php index f3f6352e5d58b7264677d46936761ccdfef3a0a7..ab03d41171eeb8d0324868150a4125ad741f72cc 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php @@ -72,7 +72,7 @@ function testCommentEnable() { $edit = array(); $edit['modules[Core][comment][enable]'] = FALSE; $this->drupalPost('admin/modules', $edit, t('Save configuration')); - $this->rebuildContainer(); + $this->resetAll(); $this->assertFalse(module_exists('comment'), 'Comment module disabled.'); // Enable core content type modules (book, and poll). @@ -85,7 +85,7 @@ function testCommentEnable() { $edit = array(); $edit['modules[Core][comment][enable]'] = 'comment'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); - $this->rebuildContainer(); + $this->resetAll(); $this->assertTrue(module_exists('comment'), 'Comment module enabled.'); // Create nodes of each type. diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php index 6d213f632e2a56969836fe45f627ee5096420d44..8b0ce69290da96d704bd502d89855ef2b93dec85 100644 --- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php +++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php @@ -14,7 +14,7 @@ */ class EntityDisplayTest extends DrupalUnitTestBase { - public static $modules = array('entity', 'field', 'entity_test'); + public static $modules = array('entity_test'); public static function getInfo() { return array( @@ -27,7 +27,7 @@ public static function getInfo() { protected function setUp() { parent::setUp(); - $this->enableModules(array('field')); + $this->enableModules(array('system', 'entity', 'field')); } /** diff --git a/core/modules/field/field.module b/core/modules/field/field.module index e350a2e367c8524780337461f34644528c57377d..e30f16a3fbe3ab7c377185f5fc74d6bee13f6e3d 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -541,7 +541,7 @@ function field_modules_disabled($modules) { function field_sync_field_status() { // Refresh the 'active' and 'storage_active' columns according to the current // set of enabled modules. - $modules = array_keys(drupal_container()->get('module_handler')->getModuleList()); + $modules = module_list(); foreach ($modules as $module_name) { field_associate_fields($module_name); } diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php index d4aba03a77c994745ccd54c450172b48e451e9c7..11853b582e5b266c15400d13b7ac0a44a03f5463 100644 --- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php +++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php @@ -108,7 +108,7 @@ function testEnableForumField() { $edit['modules[Core][forum][enable]'] = FALSE; $this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); - $this->rebuildContainer(); + system_list_reset(); $this->assertFalse(module_exists('forum'), 'Forum module is not enabled.'); // Attempt to re-enable the Forum module and ensure it does not try to @@ -117,7 +117,7 @@ function testEnableForumField() { $edit['modules[Core][forum][enable]'] = 'forum'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); - $this->rebuildContainer(); + system_list_reset(); $this->assertTrue(module_exists('forum'), 'Forum module is enabled.'); } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php index eacf9dffa79b3139fc946b09bf5f48647d194e1a..c4422aaa891b8df1004a0e98d7ce44bd890c377f 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php @@ -15,8 +15,6 @@ class RdfSchemaSerializationTest extends DrupalUnitTestBase { - public static $modules = array('system'); - public static function getInfo() { return array( 'name' => 'Site schema JSON-LD serialization', @@ -29,8 +27,9 @@ public static function getInfo() { * Tests the serialization of site schemas. */ function testSchemaSerialization() { - // url() requires the {url_alias} table. - $this->installSchema('system', 'url_alias'); + // In order to use url() the url_alias table must be installed, so system + // is enabled. + $this->enableModules(array('system')); $entity_type = $bundle = 'entity_test'; diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php index 8aea763917a03b3e34191b8f4a82bf339f94786c..436b371b5b3f26a071c825eab74c9508b9a2075d 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php @@ -139,7 +139,7 @@ protected function languageNegotiationUpdate($op = 'enable') { $function = "module_{$op}"; $function($modules); // Reset hook implementation cache. - $this->container->get('module_handler')->resetImplementations(); + module_implements_reset(); } drupal_static_reset('language_types_info'); diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php b/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php index c5d0ddeaa1df659aacd415739022d48a73982cdb..a6c4ea947dfe5b077aaa055b034e76c3defc54fc 100644 --- a/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php +++ b/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php @@ -58,12 +58,11 @@ public function getDerivativeDefinitions(array $base_plugin_definition) { $available_layout_providers = array(); // Add all modules as possible layout providers. - // @todo Inject the module handler. - foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) { + foreach (module_list() as $module) { $available_layout_providers[$module] = array( 'type' => 'module', 'provider' => $module, - 'dir' => dirname($filename), + 'dir' => drupal_get_path('module', $module), ); } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php index b9348517d3f3d0f35b5c7b25a82b9095d0bb54da..bd1f5a3022a9e159059d2a58847772443bea9f7b 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php @@ -315,7 +315,6 @@ function testUpdateProjects() { // modules not hidden. locale_test_system_info_alter() modifies the project // info of the locale_test and locale_test_translate modules. state()->set('locale.test_system_info_alter', TRUE); - $this->resetAll(); // Check if interface translation data is collected from hook_info. $projects = locale_translation_project_list(); @@ -333,7 +332,6 @@ function testUpdateProjectsHidden() { // Make the test modules look like a normal custom module. state()->set('locale.test_system_info_alter', TRUE); - $this->resetAll(); // Set test condition: include disabled modules when building a project list. $edit = array( diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php index b17e37100a36f0c16258166c94cc4ad2bc862d26..b09df752e80e38adb3c0e7261158d38fe671e58c 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php @@ -50,6 +50,18 @@ abstract class DrupalUnitTestBase extends UnitTestBase { */ public static $modules = array(); + /** + * Fixed module list being used by this test. + * + * @var array + * An associative array containing the required data for the $fixed_list + * argument of module_list(). + * + * @see UnitTestBase::setUp() + * @see UnitTestBase::enableModules() + */ + private $moduleList = array(); + private $moduleFiles; private $themeFiles; private $themeData; @@ -92,6 +104,8 @@ protected function setUp() { $this->kernel = new DrupalKernel('testing', TRUE, drupal_classloader(), FALSE); $this->kernel->boot(); + // Ensure that the module list is initially empty. + $this->moduleList = array(); // Collect and set a fixed module list. $class = get_class($this); $modules = array(); @@ -118,15 +132,11 @@ public function containerBuild($container) { global $conf; // Keep the container object around for tests. $this->container = $container; - $container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); - $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend'); - $container ->register('config.storage', 'Drupal\Core\Config\FileStorage') ->addArgument($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); - $conf['keyvalue_default'] = 'keyvalue.memory'; $container->set('keyvalue.memory', $this->keyValueFactory); if (!$container->has('keyvalue')) { @@ -162,7 +172,7 @@ protected function installSchema($module, $table) { // file depends on many other factors. To prevent differences in test // behavior and non-reproducible test failures, we only allow the schema of // explicitly loaded/enabled modules to be installed. - if (!$this->container->get('module_handler')->moduleExists($module)) { + if (!module_exists($module)) { throw new \RuntimeException(format_string("'@module' module is not enabled.", array( '@module' => $module, ))); @@ -197,30 +207,27 @@ protected function installSchema($module, $table) { * Defaults to TRUE. If FALSE, the new modules are only added to the fixed * module list and loaded. * - * @todo Remove $install argument and replace all callers that do not pass - * FALSE with module_enable(). + * @todo Remove this method as soon as there is an Extensions service + * implementation that is able to manage a fixed module list. */ protected function enableModules(array $modules, $install = TRUE) { - if ($install) { - module_enable($modules, FALSE); - } - // Explicitly set the list of modules in the extension handler. - else { - $module_handler = $this->container->get('module_handler'); - $module_filenames = $module_handler->getModuleList(); - foreach ($modules as $module) { - $module_filenames[$module] = drupal_get_filename('module', $module); + // Set the modules in the fixed module_list(). + $new_enabled = array(); + foreach ($modules as $module) { + $this->moduleList[$module]['filename'] = drupal_get_filename('module', $module); + $new_enabled[$module] = dirname($this->moduleList[$module]['filename']); + module_list(NULL, $this->moduleList); + + // Call module_enable() to enable (install) the new module. + if ($install) { + module_enable(array($module), FALSE); } - $module_handler->setModuleList($module_filenames); - $module_handler->resetImplementations(); - $this->kernel->updateModules($module_filenames, $module_filenames); } - // Regardless of loaded or installed, ensure isLoaded() is TRUE in order to - // make theme() work. - // Note that the kernel has rebuilt the container; this $module_handler is - // no longer the $module_handler instance from above. - $module_handler = $this->container->get('module_handler'); - $module_handler->reload(); + // Otherwise, only ensure that the new modules are loaded. + if (!$install) { + module_load_all(FALSE, TRUE); + module_implements_reset(); + } } } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index 79e6d9c60d154acc8c605b05efb97e9285335bf3..e8068fade6dd0028392ed68dfb959d361cf60c9b 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -921,24 +921,26 @@ protected function prepareConfigDirectories() { /** * Rebuild drupal_container(). * - * Use this to build a new kernel and service container. For example, when the - * list of enabled modules is changed via the internal browser, in which case - * the test process still contains an old kernel and service container with an - * old module list. - * * @todo Fix http://drupal.org/node/1708692 so that module enable/disable * changes are immediately reflected in drupal_container(). Until then, * tests can invoke this workaround when requiring services from newly * enabled modules to be immediately available in the same request. - * - * @see TestBase::prepareEnvironment() - * @see TestBase::tearDown() */ protected function rebuildContainer() { + // Create a new DrupalKernel for testing purposes, now that all required + // modules have been enabled. This also stores a new dependency injection + // container in drupal_container(). Drupal\simpletest\TestBase::tearDown() + // restores the original container. + // @see Drupal\Core\DrupalKernel::initializeContainer() $this->kernel = new DrupalKernel('testing', FALSE, drupal_classloader(), FALSE); + // Booting the kernel is necessary to initialize the new DIC. While + // normally the kernel gets booted on demand in + // Symfony\Component\HttpKernel\handle(), this kernel needs manual booting + // as it is not used to handle a request. $this->kernel->boot(); - // DrupalKernel replaces the container in drupal_container() with a - // different object, so we need to replace the instance on this test class. + // The DrupalKernel does not update the container in drupal_container(), but + // replaces it with a new object. We therefore need to replace the minimal + // boostrap container that has been set up by TestBase::prepareEnvironment(). $this->container = drupal_container(); } @@ -1031,6 +1033,10 @@ protected function tearDown() { drupal_valid_test_ua($this->originalPrefix); } + // Reset module list and module load status. + module_list_reset(); + module_load_all(FALSE, TRUE); + // Restore original shutdown callbacks. $callbacks = &drupal_register_shutdown_function(); $callbacks = $this->originalShutdownCallbacks; diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php index 242338efc533d23b336fbec22fff046372c1d4cd..6bca9d6aca49221296048d30201c0e2d613ecbe6 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php @@ -39,7 +39,7 @@ function testSetUp() { // Verify that specified $modules have been loaded. $this->assertTrue(function_exists('entity_test_permission'), "$module.module was loaded."); // Verify that there is a fixed module list. - $this->assertIdentical(array_keys(drupal_container()->get('module_handler')->getModuleList()), array($module)); + $this->assertIdentical(module_list(), array($module => $module)); $this->assertIdentical(module_implements('permission'), array($module)); // Verify that no modules have been installed. @@ -54,9 +54,9 @@ function testEnableModulesLoad() { // Verify that the module does not exist yet. $this->assertFalse(module_exists($module), "$module module not found."); - $list = array_keys(drupal_container()->get('module_handler')->getModuleList()); - $this->assertFalse(in_array($module, $list), "$module module not found in the extension handler's module list."); - $list = module_implements('permission'); + $list = module_list(); + $this->assertFalse(in_array($module, $list), "$module module in module_list() not found."); + $list = module_list('permission'); $this->assertFalse(in_array($module, $list), "{$module}_permission() in module_implements() not found."); // Enable the module. @@ -64,9 +64,9 @@ function testEnableModulesLoad() { // Verify that the module exists. $this->assertTrue(module_exists($module), "$module module found."); - $list = array_keys(drupal_container()->get('module_handler')->getModuleList()); - $this->assertTrue(in_array($module, $list), "$module module found in the extension handler's module list."); - $list = module_implements('permission'); + $list = module_list(); + $this->assertTrue(in_array($module, $list), "$module module in module_list() found."); + $list = module_list('permission'); $this->assertTrue(in_array($module, $list), "{$module}_permission() in module_implements() found."); } @@ -83,9 +83,9 @@ function testEnableModulesInstall() { // Verify that the module does not exist yet. $this->assertFalse(module_exists($module), "$module module not found."); - $list = array_keys(drupal_container()->get('module_handler')->getModuleList()); - $this->assertFalse(in_array($module, $list), "$module module not found in the extension handler's module list."); - $list = module_implements('permission'); + $list = module_list(); + $this->assertFalse(in_array($module, $list), "$module module in module_list() not found."); + $list = module_list('permission'); $this->assertFalse(in_array($module, $list), "{$module}_permission() in module_implements() not found."); $this->assertFalse(db_table_exists($table), "'$table' database table not found."); @@ -97,9 +97,9 @@ function testEnableModulesInstall() { // Verify that the enabled module exists. $this->assertTrue(module_exists($module), "$module module found."); - $list = array_keys(drupal_container()->get('module_handler')->getModuleList()); - $this->assertTrue(in_array($module, $list), "$module module found in the extension handler's module list."); - $list = module_implements('permission'); + $list = module_list(); + $this->assertTrue(in_array($module, $list), "$module module in module_list() found."); + $list = module_list('permission'); $this->assertTrue(in_array($module, $list), "{$module}_permission() in module_implements() found."); $this->assertTrue(db_table_exists($table), "'$table' database table found."); @@ -180,68 +180,4 @@ function testInstallSchema() { $this->assertTrue($schema, "'$table' table schema found."); } - /** - * Tests that the fixed module list is retained after enabling and installing modules. - */ - function testEnableModulesFixedList() { - // entity_test is loaded via $modules; its entity type should exist. - $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); - $this->assertTrue(TRUE == entity_get_info('entity_test')); - - // Load some additional modules; entity_test should still exist. - $this->enableModules(array('entity', 'field', 'field_sql_storage', 'text', 'entity_test'), FALSE); - $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); - $this->assertTrue(TRUE == entity_get_info('entity_test')); - - // Install some other modules; entity_test should still exist. - module_enable(array('field', 'field_sql_storage', 'field_test'), FALSE); - $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); - $this->assertTrue(TRUE == entity_get_info('entity_test')); - - // Disable one of those modules; entity_test should still exist. - module_disable(array('field_test')); - $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); - $this->assertTrue(TRUE == entity_get_info('entity_test')); - - // Set the weight of a module; entity_test should still exist. - module_set_weight('entity', -1); - $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); - $this->assertTrue(TRUE == entity_get_info('entity_test')); - - // Reactivate the disabled module without enabling it. - $this->enableModules(array('field_test'), FALSE); - - // Create a field and an instance. - $display = entity_create('entity_display', array( - 'targetEntityType' => 'entity_test', - 'bundle' => 'entity_test', - 'viewMode' => 'default', - )); - $field = array( - 'field_name' => 'test_field', - 'type' => 'test_field' - ); - field_create_field($field); - $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ); - field_create_instance($instance); - } - - /** - * Tests that theme() works right after loading a module. - */ - function testEnableModulesTheme() { - $element = array( - '#type' => 'container', - '#markup' => 'Foo', - '#attributes' => array(), - ); - $this->enableModules(array('system'), FALSE); - // theme() throws an exception if modules are not loaded yet. - drupal_render($element); - } - } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php index d7bd2253bd0311f384933a45967dcc387f85ae44..648aa4251708984b25e9910cbac1aa1bb9a0405c 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php @@ -56,6 +56,9 @@ protected function setUp() { $conf = array(); drupal_static_reset(); + // Enforce an empty module list. + module_list(NULL, array()); + $conf['file_public_path'] = $this->public_files_directory; // Change the database prefix. diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php index 525de36635a494632a08148da53854e583f71796..f301257b0574084c57b46c635f93c4d0c1eef1f8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php @@ -36,11 +36,6 @@ protected function createCacheBackend($bin) { * Installs system schema. */ public function setUpCacheBackend() { - // Calling drupal_install_schema() entails a call to module_invoke, for which - // we need a ModuleHandler. Register one to the container. - // @todo Use DrupalUnitTestBase. - $this->container->register('module_handler', 'Drupal\Core\Extension\ModuleHandler'); - drupal_install_schema('system'); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php index 2221aafe66f0d13e6ae70f9af42d4bfc760f3039..e8602f4e9701a23b8d2107b0b37278c6c2451e05 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php @@ -43,7 +43,7 @@ function testEnableDisable() { // Remove already enabled modules (via installation profile). // @todo Remove this after removing all dependencies from Testing profile. - foreach ($this->container->get('module_handler')->getModuleList() as $dependency => $filename) { + foreach (module_list() as $dependency) { // Exclude required modules. Only installation profile "suggestions" can // be disabled and uninstalled. if (isset($modules[$dependency])) { 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 64fc8e372f973e8b4c79661d3a7807ecd05ccdb3..85a41841d9528011fd6a60d684892ef41866e13e 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php @@ -25,7 +25,7 @@ public static function getInfo() { } /** - * The basic functionality of retrieving enabled modules. + * The basic functionality of module_list(). */ function testModuleList() { // Build a list of modules, sorted alphabetically. @@ -36,8 +36,8 @@ function testModuleList() { $module_list[] = 'standard'; sort($module_list); - // Compare this list to the one returned by the extension handler. We expect - // them to match, since all default profile modules have a weight equal to 0 + // Compare this list to the one returned by module_list(). We expect them + // to match, since all default profile modules have a weight equal to 0 // (except for block.module, which has a lower weight but comes first in // the alphabet anyway). $this->assertModuleList($module_list, t('Standard profile')); @@ -50,7 +50,8 @@ function testModuleList() { // Try to mess with the module weights. module_set_weight('contact', 20); - + // Reset the module list. + system_list_reset(); // Move contact to the end of the array. unset($module_list[array_search('contact', $module_list)]); $module_list[] = 'contact'; @@ -58,26 +59,27 @@ function testModuleList() { // Test the fixed list feature. $fixed_list = array( - 'system' => 'core/modules/system/system.module', - 'menu' => 'core/modules/menu/menu.module', + 'system' => array('filename' => drupal_get_path('module', 'system')), + 'menu' => array('filename' => drupal_get_path('module', 'menu')), ); - $this->container->get('module_handler')->setModuleList($fixed_list); + module_list(NULL, $fixed_list); $new_module_list = array_combine(array_keys($fixed_list), array_keys($fixed_list)); $this->assertModuleList($new_module_list, t('When using a fixed list')); + // Reset the module list. + module_list_reset(); + $this->assertModuleList($module_list, t('After reset')); } /** - * Assert that the extension handler returns the expected values. + * Assert that module_list() return the expected values. * * @param $expected_values * The expected values, sorted by weight and module name. */ protected function assertModuleList(Array $expected_values, $condition) { - $expected_values = array_values(array_unique($expected_values)); - $enabled_modules = array_keys($this->container->get('module_handler')->getModuleList()); - $enabled_modules = sort($enabled_modules); - $this->assertEqual($expected_values, $enabled_modules, format_string('@condition: extension handler returns correct results', array('@condition' => $condition))); + $expected_values = array_combine($expected_values, $expected_values); + $this->assertEqual($expected_values, module_list(), format_string('@condition: module_list() returns correct results', array('@condition' => $condition))); } /** @@ -101,11 +103,12 @@ function testModuleImplements() { // already loaded when the cache is rebuilt. // For that activate the module_test which provides the file to load. module_enable(array('module_test')); - $module_handler = drupal_container()->get('module_handler'); - $module_handler->loadAll(); + module_load_include('inc', 'module_test', 'module_test.file'); - $modules = $module_handler->getImplementations('test_hook'); + $modules = module_implements('test_hook'); + $static = drupal_static('module_implements'); $this->assertTrue(in_array('module_test', $modules), 'Hook found.'); + $this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.'); } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php index 7804b0a486aafb2cfbb7e0938728513f9beb8bf0..916555d4817c8f1c3ea5148675bf7f93109919c3 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php @@ -57,7 +57,6 @@ function assertTableCount($base_table, $count = TRUE) { * The name of the module. */ function assertModuleTablesExist($module) { - $this->rebuildContainer(); $tables = array_keys(drupal_get_schema_unprocessed($module)); $tables_exist = TRUE; foreach ($tables as $table) { @@ -145,7 +144,7 @@ function assertNoModuleConfig($module) { * Expected module state. */ function assertModules(array $modules, $enabled) { - $this->rebuildContainer(); + system_list_reset(); foreach ($modules as $module) { if ($enabled) { $message = 'Module "@module" is enabled.'; @@ -153,7 +152,7 @@ function assertModules(array $modules, $enabled) { else { $message = 'Module "@module" is not enabled.'; } - $this->assertEqual($this->container->get('module_handler')->moduleExists($module), $enabled, format_string($message, array('@module' => $module))); + $this->assertEqual(module_exists($module), $enabled, format_string($message, array('@module' => $module))); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php b/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php index 4e79ae92c3b32a9db2907c92ed4fb3cb3855d9c8..2de5ad346ea7fcda32aac20a512102042ee7c66d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php @@ -56,7 +56,7 @@ function testMainContentFallback() { $edit['modules[Core][block][enable]'] = FALSE; $this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); - $this->rebuildContainer(); + system_list_reset(); $this->assertFalse(module_exists('block'), 'Block module disabled.'); // At this point, no region is filled and fallback should be triggered. @@ -90,7 +90,7 @@ function testMainContentFallback() { $edit['modules[Core][block][enable]'] = 'block'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); - $this->rebuildContainer(); + system_list_reset(); $this->assertTrue(module_exists('block'), 'Block module re-enabled.'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php index 5ab43ca6c5f63c79aa2b660f4f18e72f88bb24df..7ea187f572dfbc1a2b70c72b97d50aaebd32a663 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php @@ -40,7 +40,7 @@ function testRaceCondition() { // Directly instantiate the theme registry, this will cause a base cache // entry to be written in __construct(). - $registry = new ThemeRegistry($cid, 'cache', array('theme_registry' => TRUE), $this->container->get('module_handler')->isLoaded()); + $registry = new ThemeRegistry($cid, 'cache', array('theme_registry' => TRUE)); $this->assertTrue(cache()->get($cid), 'Cache entry was created.'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php index 6e9b383a21565217bdf1074270979aee66fdd4ed..5267300f0695b240c9f3a670fd0867a0fef2d2c1 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php @@ -175,19 +175,9 @@ function testRegistryRebuild() { $this->assertIdentical(theme('theme_test_foo', array('foo' => 'a')), 'a', 'The theme registry contains theme_test_foo.'); module_disable(array('theme_test'), FALSE); - // After enabling/disabling a module during a test, we need to rebuild the - // container and ensure the extension handler is loaded, otherwise theme() - // throws an exception. - $this->rebuildContainer(); - $this->container->get('module_handler')->loadAll(); $this->assertIdentical(theme('theme_test_foo', array('foo' => 'b')), '', 'The theme registry does not contain theme_test_foo, because the module is disabled.'); module_enable(array('theme_test'), FALSE); - // After enabling/disabling a module during a test, we need to rebuild the - // container and ensure the extension handler is loaded, otherwise theme() - // throws an exception. - $this->rebuildContainer(); - $this->container->get('module_handler')->loadAll(); $this->assertIdentical(theme('theme_test_foo', array('foo' => 'c')), 'c', 'The theme registry contains theme_test_foo again after re-enabling the module.'); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php index 499acf28e73e81bce5e7bbddf0df4aaca941b202..8d4da5197da020d05e618c64f1e12ca104ef20ef 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php @@ -82,7 +82,7 @@ public function testBasicMinimalUpgrade() { $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete'); // Verify that all required modules are enabled. - $enabled = $this->container->get('module_handler')->getModuleList(); + $enabled = module_list(); $required = array_filter(system_rebuild_module_data(), function ($data) { return !empty($data->info['required']); }); diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php index b02d5ffd79b00cab59d619e46c77474974427400..c85c912aa42499e00bc1cc9fb9e39363b1a74dfd 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php @@ -37,7 +37,7 @@ public function testDisabledUpgrade() { $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Get enabled modules. - $enabled = drupal_container()->get('module_handler')->getModuleList(); + $enabled = module_list(); // Get all available modules. $available = system_rebuild_module_data(); // Filter out hidden test modules. diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/SystemUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/SystemUpgradePathTest.php index 2929e71c145a518ecda91f1b8d566f563d85cb80..2384f58b3c3ae2b3cbb8076002588375a376e16a 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/SystemUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/SystemUpgradePathTest.php @@ -115,6 +115,8 @@ public function testVariableUpgrade() { public function testFrontpageUpgrade() { $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); + // Reset the module enable list to get the current result. + module_list_reset(); $this->assertTrue(module_exists('views'), 'Views is enabled after the upgrade.'); } 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 c4dda65035cb39154d8e0da44a843e062bbb3fc4..106d726a8b5ff08497e520fa2850509f91fba344 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php @@ -268,8 +268,9 @@ protected function performUpgrade($register_errors = TRUE) { // Reload module list for modules that are enabled in the test database // but not on the test client. - drupal_container()->get('module_handler')->resetImplementations(); - drupal_container()->get('module_handler')->reload(); + system_list_reset(); + module_implements_reset(); + module_load_all(FALSE, TRUE); // Rebuild the container and all caches. $this->rebuildContainer(); diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 37a2bf23fb00fd305ac0dac5fc4e5aeed9af4868..c3c2ce4645c287e48ae9fabe27180b11e537c1fc 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -1204,7 +1204,7 @@ function system_modules_submit($form, &$form_state) { // Gets list of modules prior to install process, unsets $form_state['storage'] // so we don't get redirected back to the confirmation form. - $pre_install_list = drupal_container()->get('module_handler')->getModuleList(); + $pre_install_list = module_list(); unset($form_state['storage']); // Reverse the 'enable' list, to order dependencies before dependents. @@ -1216,7 +1216,7 @@ function system_modules_submit($form, &$form_state) { // Gets module list after install process, flushes caches and displays a // message if there are changes. - $post_install_list = drupal_container()->get('module_handler')->getModuleList(); + $post_install_list = module_list(); if ($pre_install_list != $post_install_list) { drupal_flush_all_caches(); drupal_set_message(t('The configuration options have been saved.')); diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 68dd42276fb7eaf67082a79d29721863bec02387..c0e3fe61bf09d239d3a069d7830fdf433334be53 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -400,7 +400,7 @@ function system_requirements($phase) { ); // Check installed modules. - foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) { + foreach (module_list() as $module) { $updates = drupal_get_schema_versions($module); if ($updates !== FALSE) { $default = drupal_get_installed_schema_version($module); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 17015c6276074cecd6360245bcf92c9bd5d4adcd..336f84b5008df717842669f9e3727d3350c686e4 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2777,7 +2777,7 @@ function system_get_info($type, $name = NULL) { $info = array(); if ($type == 'module') { $data = system_rebuild_module_data(); - foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) { + foreach (module_list() as $module) { $info[$module] = $data[$module]->info; } } @@ -2920,7 +2920,7 @@ function system_rebuild_module_data() { $record->schema_version = SCHEMA_UNINSTALLED; $files[$module] = $record->filename; } - $modules = drupal_container()->get('module_handler')->buildModuleDependencies($modules); + $modules = _module_build_dependencies($modules); $modules_cache = $modules; // Store filenames to allow system_list() and drupal_get_filename() to diff --git a/core/scripts/dump-database-d6.sh b/core/scripts/dump-database-d6.sh index 106568d86d07dd5e16f25ad61a4e3a1da7ffa72c..d39bb4306d8314f8a2085e177a148b4f1ba7dbea 100644 --- a/core/scripts/dump-database-d6.sh +++ b/core/scripts/dump-database-d6.sh @@ -44,7 +44,7 @@ ENDOFHEADER; -foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) { +foreach (module_list() as $module) { $output .= " * - $module\n"; } $output .= " */\n\n"; diff --git a/core/scripts/dump-database-d7.sh b/core/scripts/dump-database-d7.sh index 3b8597dde9ee60aa9d9d4d8e4b7606fc010d740f..3440fa25a758e59a1a6b920e3f4564798f5f2f63 100644 --- a/core/scripts/dump-database-d7.sh +++ b/core/scripts/dump-database-d7.sh @@ -45,7 +45,7 @@ ENDOFHEADER; -foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) { +foreach (module_list() as $module) { $output .= " * - $module\n"; } $output .= " */\n\n"; diff --git a/core/update.php b/core/update.php index 69f058ada57ea6a8a2e7cd7020a64023a4c63d08..17b44fd096a03c9183a4d8e2b944affb5ec2708c 100644 --- a/core/update.php +++ b/core/update.php @@ -435,14 +435,13 @@ function update_check_requirements($skip_warnings = FALSE) { // Load module basics. include_once DRUPAL_ROOT . '/core/includes/module.inc'; - $module_list['system'] = 'core/modules/system/system.module'; - $module_handler = drupal_container()->get('module_handler'); - $module_handler->setModuleList($module_list); - $module_handler->load('system'); + $module_list['system']['filename'] = 'core/modules/system/system.module'; + module_list(NULL, $module_list); + drupal_load('module', 'system'); - // Reset the module implementations cache so that any new hook implementations + // Reset the module_implements() cache so that any new hook implementations // in updated code are picked up. - $module_handler->resetImplementations(); + module_implements_reset(); // Set up $language, since the installer components require it. drupal_language_initialize();