Newer
Older
/**
* @file
* API for loading and interacting with Drupal modules.
*/
Dries Buytaert
committed
use Drupal\Component\Graph\Graph;
use Drupal\Component\Utility\NestedArray;
Angie Byron
committed
use Symfony\Component\DependencyInjection\ContainerInterface;
Dries Buytaert
committed
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Builds a list of bootstrap modules and enabled modules and themes.
Dries Buytaert
committed
*
* @param $type
* The type of list to return:
* - module_enabled: All enabled modules.
* - bootstrap: All enabled modules required for bootstrap.
* - theme: All themes.
Dries Buytaert
committed
*
* @return
Dries Buytaert
committed
* An associative array of modules or themes, keyed by name. For $type
* 'bootstrap' and 'module_enabled', the array values equal the keys.
* For $type 'theme', the array values are objects representing the
* respective database row, with the 'info' property already unserialized.
Dries Buytaert
committed
*
* @see list_themes()
*
* @todo There are too many layers/levels of caching involved for system_list()
* data. Consider to add a config($name, $cache = TRUE) argument to allow
* callers like system_list() to force-disable a possible configuration
* storage controller cache or some other way to circumvent it/take it over.
Dries Buytaert
committed
*/
function system_list($type) {
$lists = &drupal_static(__FUNCTION__);
if ($cached = cache('bootstrap')->get('system_list')) {
$lists = $cached->data;
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])) {
$lists['filepaths'][] = array(
'type' => 'theme',
'name' => $name,
'filepath' => $theme->filename,
);
}
}
// @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'];
Dries Buytaert
committed
}
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']);
Dries Buytaert
committed
}
return $lists[$type];
}
/**
Jennifer Hodgdon
committed
* Resets all system_list() caches.
*/
function system_list_reset() {
drupal_static_reset('system_list');
Dries Buytaert
committed
drupal_static_reset('system_rebuild_module_data');
Angie Byron
committed
drupal_static_reset('list_themes');
cache('bootstrap')->delete('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
// invocation. When enabling a module that implements hook_system_info_alter()
// to inject a new (testing) theme or manipulate an existing theme, then that
// will cause system_list_reset() to be called, but theme data is not
// necessarily rebuilt afterwards.
// @todo Obsolete with proper installation status for themes.
state()->delete('system.theme.data');
}
/**
* Registers an extension in runtime registries for execution.
*
* @param string $type
* The extension type; e.g., 'module' or 'theme'.
* @param string $name
* The internal name of the extension; e.g., 'node'.
* @param string $uri
* The relative URI of the primary extension file; e.g.,
* 'core/modules/node/node.module'.
*/
function system_register($type, $name, $uri) {
drupal_get_filename($type, $name, $uri);
drupal_classloader_register($name, dirname($uri));
}
Jennifer Hodgdon
committed
* Loads a module's installation hooks.
Angie Byron
committed
*
* @param $module
* The name of the module (without the .module extension).
*
* @return
* The name of the module's install file, if successful; FALSE otherwise.
*/
function module_load_install($module) {
// Make sure the installation API is available
Nate Lampton
committed
include_once DRUPAL_ROOT . '/core/includes/install.inc';
Angie Byron
committed
return module_load_include('install', $module);
Dries Buytaert
committed
}
/**
Jennifer Hodgdon
committed
* Loads a module include file.
Dries Buytaert
committed
*
* Examples:
* @code
* // Load node.admin.inc from the node module.
* module_load_include('inc', 'node', 'node.admin');
* // Load content_types.inc from the node module.
Dries Buytaert
committed
* module_load_include('inc', 'node', 'content_types');
* @endcode
Dries Buytaert
committed
*
Angie Byron
committed
* Do not use this function to load an install file, use module_load_install()
* instead. Do not use this function in a global context since it requires
* Drupal to be fully bootstrapped, use require_once DRUPAL_ROOT . '/path/file'
* instead.
*
Dries Buytaert
committed
* @param $type
* The include file's type (file extension).
* @param $module
* The module to which the include file belongs.
* @param $name
Dries Buytaert
committed
* (optional) The base file name (without the $type extension). If omitted,
* $module is used; i.e., resulting in "$module.$type" by default.
Angie Byron
committed
*
* @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.
Dries Buytaert
committed
*/
function module_load_include($type, $module, $name = NULL) {
Dries Buytaert
committed
if (!isset($name)) {
Dries Buytaert
committed
$name = $module;
}
if (function_exists('drupal_get_path')) {
Angie Byron
committed
$file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type";
if (is_file($file)) {
require_once $file;
return $file;
}
Dries Buytaert
committed
}
Angie Byron
committed
return FALSE;
Dries Buytaert
committed
}
* Enables or installs a given list of modules.
* Definitions:
* - "Enabling" is the process of activating a module for use by Drupal.
* - "Disabling" is the process of deactivating a module.
* - "Installing" is the process of enabling it for the first time or after it
* has been uninstalled.
* - "Uninstalling" is the process of removing all traces of a module.
*
* Order of events:
* - Gather and add module dependencies to $module_list (if applicable).
* - For each module that is being enabled:
* - Install module schema and update system registries and caches.
* - If the module is being enabled for the first time or had been
* uninstalled, invoke hook_install() and add it to the list of installed
* modules.
* - Invoke hook_enable().
* - Invoke hook_modules_installed().
* - Invoke hook_modules_enabled().
Neil Drumm
committed
* @param $module_list
* An array of module names.
Angie Byron
committed
* @param $enable_dependencies
* If TRUE, dependencies will automatically be added and enabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
*
Angie Byron
committed
* @return
* FALSE if one or more dependencies are missing, TRUE otherwise.
*
* @see hook_install()
* @see hook_enable()
* @see hook_modules_installed()
* @see hook_modules_enabled()
function module_enable($module_list, $enable_dependencies = TRUE) {
Angie Byron
committed
if ($enable_dependencies) {
// Get all module data so we can find dependencies and sort.
$module_data = system_rebuild_module_data();
// Create an associative array with weights as values.
$module_list = array_flip(array_values($module_list));
while (list($module) = each($module_list)) {
if (!isset($module_data[$module])) {
// This module is not found in the filesystem, abort.
return FALSE;
}
if ($module_data[$module]->status) {
// Skip already enabled modules.
unset($module_list[$module]);
continue;
}
$module_list[$module] = $module_data[$module]->sort;
// Add dependencies to the list, with a placeholder weight.
// The new modules will be processed as the while loop continues.
Dries Buytaert
committed
foreach (array_keys($module_data[$module]->requires) as $dependency) {
Angie Byron
committed
if (!isset($module_list[$dependency])) {
$module_list[$dependency] = 0;
}
}
}
if (!$module_list) {
// Nothing to do. All modules already enabled.
return TRUE;
}
// Sort the module list by pre-calculated weights.
arsort($module_list);
$module_list = array_keys($module_list);
}
Dries Buytaert
committed
// Required for module installation checks.
Nate Lampton
committed
include_once DRUPAL_ROOT . '/core/includes/install.inc';
Dries Buytaert
committed
$modules_installed = array();
$modules_enabled = array();
$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');
Neil Drumm
committed
foreach ($module_list as $module) {
Dries Buytaert
committed
// 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);
if ($weight === NULL) {
$weight = 0;
}
$module_config
->set("enabled.$module", $weight)
->set('enabled', module_config_sort($module_config->get('enabled')))
->save();
$disabled_config
->clear($module)
->save();
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// 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);
Neil Drumm
committed
module_load_install($module);
Dries Buytaert
committed
// 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.
Dries Buytaert
committed
system_list_reset();
// Refresh the list of modules that implement bootstrap hooks.
// @see bootstrap_hooks()
Dries Buytaert
committed
_system_update_bootstrap_status();
Angie Byron
committed
// 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.
Angie Byron
committed
if ($kernel = drupal_container()->get('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
$kernel->updateModules($module_filenames, $module_filenames);
Angie Byron
committed
}
Dries Buytaert
committed
// Refresh the schema to include it.
drupal_get_schema(NULL, TRUE);
// Update the theme registry to include it.
drupal_theme_rebuild();
Dries Buytaert
committed
// Allow modules to react prior to the installation of a module.
module_invoke_all('modules_preinstall', array($module));
Dries Buytaert
committed
catch
committed
// Clear the entity info cache before importing new configuration.
entity_info_cache_clear();
Dries Buytaert
committed
// Now install the module if necessary.
if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) {
drupal_install_schema($module);
Angie Byron
committed
// Set the schema version to the number of the last update provided
// by the module.
Dries Buytaert
committed
$versions = drupal_get_schema_versions($module);
Angie Byron
committed
$version = $versions ? max($versions) : SCHEMA_INSTALLED;
// Install default configuration of the module.
config_install_default_config('module', $module);
Angie Byron
committed
// If the module has no current updates, but has some that were
// previously removed, set the version to the value of
// hook_update_last_removed().
if ($last_removed = module_invoke($module, 'update_last_removed')) {
$version = max($version, $last_removed);
}
drupal_set_installed_schema_version($module, $version);
Dries Buytaert
committed
// Allow the module to perform install tasks.
module_invoke($module, 'install');
Dries Buytaert
committed
// Record the fact that it was installed.
$modules_installed[] = $module;
Angie Byron
committed
watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
Dries Buytaert
committed
}
Neil Drumm
committed
catch
committed
// Allow modules to react prior to the enabling of a module.
entity_info_cache_clear();
Dries Buytaert
committed
module_invoke_all('modules_preenable', array($module));
Dries Buytaert
committed
// Enable the module.
module_invoke($module, 'enable');
// Record the fact that it was enabled.
$modules_enabled[] = $module;
Angie Byron
committed
watchdog('system', '%module module enabled.', array('%module' => $module), WATCHDOG_INFO);
}
Neil Drumm
committed
}
Dries Buytaert
committed
// If any modules were newly installed, invoke hook_modules_installed().
if (!empty($modules_installed)) {
Dries Buytaert
committed
module_invoke_all('modules_installed', $modules_installed);
Dries Buytaert
committed
// If any modules were newly enabled, invoke hook_modules_enabled().
if (!empty($modules_enabled)) {
module_invoke_all('modules_enabled', $modules_enabled);
}
Angie Byron
committed
return TRUE;
Jennifer Hodgdon
committed
* Disables a given set of modules.
* @param $module_list
* An array of module names.
Angie Byron
committed
* @param $disable_dependents
* If TRUE, dependent modules will automatically be added and disabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
Angie Byron
committed
function module_disable($module_list, $disable_dependents = TRUE) {
if ($disable_dependents) {
// Get all module data so we can find dependents and sort.
$module_data = system_rebuild_module_data();
// Create an associative array with weights as values.
$module_list = array_flip(array_values($module_list));
Angie Byron
committed
$profile = drupal_get_profile();
Angie Byron
committed
while (list($module) = each($module_list)) {
if (!isset($module_data[$module]) || !$module_data[$module]->status) {
// This module doesn't exist or is already disabled, skip it.
unset($module_list[$module]);
continue;
}
$module_list[$module] = $module_data[$module]->sort;
// Add dependent modules to the list, with a placeholder weight.
// The new modules will be processed as the while loop continues.
foreach ($module_data[$module]->required_by as $dependent => $dependent_data) {
Angie Byron
committed
if (!isset($module_list[$dependent]) && $dependent != $profile) {
Angie Byron
committed
$module_list[$dependent] = 0;
}
}
}
// Sort the module list by pre-calculated weights.
asort($module_list);
$module_list = array_keys($module_list);
}
$invoke_modules = array();
Angie Byron
committed
$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) {
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;
Angie Byron
committed
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()
Dries Buytaert
committed
system_list_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);
Angie Byron
committed
_system_update_bootstrap_status();
Angie Byron
committed
// Update the kernel to exclude the disabled modules.
$enabled = $module_handler->getModuleList();
drupal_container()->get('kernel')->updateModules($enabled, $enabled);
// Update the theme registry to remove the newly-disabled module.
drupal_theme_rebuild();
Angie Byron
committed
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
/**
* Uninstalls a given list of modules.
*
* @param $module_list
* The modules to uninstall.
* @param $uninstall_dependents
* If TRUE, the function will check that all modules which depend on the
* passed-in module list either are already uninstalled or contained in the
* list, and it will ensure that the modules are uninstalled in the correct
* order. This incurs a significant performance cost, so use FALSE if you
* know $module_list is already complete and in the correct order.
*
* @return
* FALSE if one or more dependent modules are missing from the list, TRUE
* otherwise.
*/
function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) {
if ($uninstall_dependents) {
// Get all module data so we can find dependents and sort.
$module_data = system_rebuild_module_data();
// Create an associative array with weights as values.
$module_list = array_flip(array_values($module_list));
$profile = drupal_get_profile();
while (list($module) = each($module_list)) {
if (!isset($module_data[$module]) || drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED) {
// This module doesn't exist or is already uninstalled, skip it.
unset($module_list[$module]);
continue;
}
$module_list[$module] = $module_data[$module]->sort;
// If the module has any dependents which are not already uninstalled and
// not included in the passed-in list, abort. It is not safe to uninstall
// them automatically because uninstalling a module is a destructive
// operation.
foreach (array_keys($module_data[$module]->required_by) as $dependent) {
if (!isset($module_list[$dependent]) && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED && $dependent != $profile) {
return FALSE;
}
}
}
// Sort the module list by pre-calculated weights.
asort($module_list);
$module_list = array_keys($module_list);
}
catch
committed
$storage = drupal_container()->get('config.storage');
$schema_store = drupal_container()->get('keyvalue')->get('system.schema');
$disabled_config = config('system.module.disabled');
Angie Byron
committed
foreach ($module_list as $module) {
// Uninstall the module.
module_load_install($module);
module_invoke($module, 'uninstall');
drupal_uninstall_schema($module);
// Remove all configuration belonging to the module.
config_uninstall_default_config('module', $module);
Angie Byron
committed
watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
$schema_store->delete($module);
$disabled_config->clear($module);
Angie Byron
committed
}
$disabled_config->save();
drupal_get_installed_schema_version(NULL, TRUE);
Angie Byron
committed
if (!empty($module_list)) {
// Call hook_module_uninstall to let other modules act
module_invoke_all('modules_uninstalled', $module_list);
}
return TRUE;
}
/**
* @defgroup hooks Hooks
*
* Drupal's module system is based on the concept of "hooks". A hook is a PHP
* function that is named foo_bar(), where "foo" is the name of the module
* (whose filename is thus foo.module) and "bar" is the name of the hook. Each
* hook has a defined set of parameters and a specified result type.
* To extend Drupal, a module need simply implement a hook. When Drupal wishes
* to allow intervention from modules, it determines which modules implement a
* hook and calls that hook in all enabled modules that implement it.
*
* The available hooks to implement are explained here in the Hooks section of
* the developer documentation. The string "hook" is used as a placeholder for
* the module name in the hook definitions. For example, if the module file is
* called example.module, then hook_help() as implemented by that module would
* be defined as example_help().
*
* The example functions included are not part of the Drupal core, they are
* just models that you can modify. Only the hooks implemented within modules
* are executed when running Drupal.
*
* See also @link themeable the themeable group page. @endlink
Jennifer Hodgdon
committed
* Invokes a hook in a particular module.
*
* @param $module
* The name of the module (without the .module extension).
* @param $hook
* The name of the hook to invoke.
* @param ...
* Arguments to pass to the hook implementation.
* @return
* The return value of the hook implementation.
*/
Dries Buytaert
committed
function module_invoke($module, $hook) {
Dries Buytaert
committed
$args = func_get_args();
Dries Buytaert
committed
// Remove $module and $hook from the arguments.
Gábor Hojtsy
committed
unset($args[0], $args[1]);
Dries Buytaert
committed
if (module_hook($module, $hook)) {
Dries Buytaert
committed
return call_user_func_array($module . '_' . $hook, $args);
Dries Buytaert
committed
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Returns an array of modules required by core.
Dries Buytaert
committed
*/
function drupal_required_modules() {
$files = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'modules');
$required = array();
Angie Byron
committed
Jennifer Hodgdon
committed
// An installation profile is required and one must always be loaded.
Angie Byron
committed
$required[] = drupal_get_profile();
foreach ($files as $name => $file) {
$info = drupal_parse_info_file($file->uri);
if (!empty($info) && !empty($info['required']) && $info['required']) {
$required[] = $name;
}
}
Angie Byron
committed
return $required;
Dries Buytaert
committed
}
/**
* Sets weight of a particular module.
*
* The weight of uninstalled modules cannot be changed.
*
* @param string $module
* The name of the module (without the .module extension).
* @param int $weight
* An integer representing the weight of the module.
*/
function module_set_weight($module, $weight) {
// Update the module weight in the config file that contains it.
$module_config = config('system.module');
if ($module_config->get("enabled.$module") !== NULL) {
$module_config
->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);
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
return;
}
$disabled_config = config('system.module.disabled');
if ($disabled_config->get($module) !== NULL) {
$disabled_config
->set($module, $weight)
->save();
return;
}
}
/**
* Sorts the configured list of enabled modules.
*
* The list of enabled modules is expected to be ordered by weight and name.
* The list is always sorted on write to avoid the overhead on read.
*
* @param array $data
* An array of module configuration data.
*
* @return array
* An array of module configuration data sorted by weight and name.
*/
function module_config_sort($data) {
// PHP array sorting functions such as uasort() do not work with both keys and
// values at the same time, so we achieve weight and name sorting by computing
// strings with both information concatenated (weight first, name second) and
// use that as a regular string sort reference list via array_multisort(),
// compound of "[sign-as-integer][padded-integer-weight][name]"; e.g., given
// two modules and weights (spaces added for clarity):
// - Block with weight -5: 0 0000000000000000005 block
// - Node with weight 0: 1 0000000000000000000 node
$sort = array();
foreach ($data as $name => $weight) {
// Prefix negative weights with 0, positive weights with 1.
// +/- signs cannot be used, since + (ASCII 43) is before - (ASCII 45).
$prefix = (int) ($weight >= 0);
// The maximum weight is PHP_INT_MAX, so pad all weights to 19 digits.
$sort[] = $prefix . sprintf('%019d', abs($weight)) . $name;
}
array_multisort($sort, SORT_STRING, $data);
return $data;
}