Commit 2cf9e49e authored by catch's avatar catch

Revert "Issue #1331486 by katbailey, chx, sun, beejeebus, amateescu: Move...

Revert "Issue #1331486 by katbailey, chx, sun, beejeebus, amateescu: Move module_invoke_*() and friends to an Extensions class. Broke core tests after commit."

This reverts commit c80c3e18.
parent 0d74f5bf
......@@ -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();
......
......@@ -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.
*
......
......@@ -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<operation>!=|==|=|<|<=|>|>=|<>)?';
// 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<major>\d+)';
// By setting the minor version to x, branches can be matched.
$p_minor = '(?P<minor>(?:\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'])) {
......
......@@ -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');
$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);
}
......
......@@ -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');
......
This diff is collapsed.
......@@ -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();
......
......@@ -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.'));
}
......
......@@ -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();
......
......@@ -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')) {
......
......@@ -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.
*
......
......@@ -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;
......
......@@ -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();
}
......
<?php
/**
* @file
* Contains Drupal\Core\Extension\CachedModuleHandler.
*/
namespace Drupal\Core\Extension;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
/**
* Class that manages enabled modules in a Drupal installation.
*/
class CachedModuleHandler extends ModuleHandler implements CachedModuleHandlerInterface {
/**
* State key/value store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
*/
protected $state;
/**
* Cache backend for storing enabled modules.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $bootstrapCache;
/**
* Whether the cache needs to be written.
*
* @var boolean
*/
protected $cacheNeedsWriting = FALSE;
/**
* Constructs a new CachedModuleHandler object.
*/
public function __construct(array $module_list = array(), KeyValueStoreInterface $state, CacheBackendInterface $bootstrap_cache) {
parent::__construct($module_list);
$this->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])) {