diff --git a/core/core.services.yml b/core/core.services.yml index 9e82af7..3cbf64c 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -521,7 +521,7 @@ services: class: Drupal\Core\Extension\RequiredModuleUninstallValidator tags: - { name: module_install.uninstall_validator } - arguments: ['@string_translation'] + arguments: ['@string_translation', '@extension.list.module'] lazy: true theme_handler: class: Drupal\Core\Extension\ThemeHandler diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index c01aaa0..8947151 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -83,6 +83,8 @@ public function install(array $module_list, $enable_dependencies = TRUE) { $extension_config = \Drupal::configFactory()->getEditable('core.extension'); if ($enable_dependencies) { // Get all module data so we can find dependencies and sort. + // The module list needs to be reset so that it can re-scan and include + // any new modules that may have been added directly into the filesystem. $module_data = \Drupal::service('extension.list.module')->reset()->getList(); $module_list = $module_list ? array_combine($module_list, $module_list) : []; if ($missing_modules = array_diff_key($module_list, $module_data)) { diff --git a/core/lib/Drupal/Core/Extension/RequiredModuleUninstallValidator.php b/core/lib/Drupal/Core/Extension/RequiredModuleUninstallValidator.php index 8b90f0d..6c01c42 100644 --- a/core/lib/Drupal/Core/Extension/RequiredModuleUninstallValidator.php +++ b/core/lib/Drupal/Core/Extension/RequiredModuleUninstallValidator.php @@ -13,13 +13,21 @@ class RequiredModuleUninstallValidator implements ModuleUninstallValidatorInterf use StringTranslationTrait; /** + * The module extension list. + * + * @var \Drupal\Core\Extension\ModuleExtensionList + */ + protected $moduleExtensionList; + + /** * Constructs a new RequiredModuleUninstallValidator. * * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation * The string translation service. */ - public function __construct(TranslationInterface $string_translation) { + public function __construct(TranslationInterface $string_translation, ModuleExtensionList $extension_list_module) { $this->stringTranslation = $string_translation; + $this->moduleExtensionList = $extension_list_module; } /** @@ -41,11 +49,17 @@ public function validate($module) { * The name of the module. * * @return array - * The module info, or NULL if that module does not exist. + * The module info, or empty array if that module does not exist. */ protected function getModuleInfoByModule($module) { - $modules = \Drupal::service('extension.list.module')->getList(); - return isset($modules[$module]->info) ? $modules[$module]->info : []; + try { + return $this->moduleExtensionList->get($module)->info; + } + catch (\InvalidArgumentException $e) { + // @todo Replace with dedicated exception + // https://www.drupal.org/project/drupal/issues/2940203 + return []; + } } } diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php index 02a08a2..96e2db5 100644 --- a/core/modules/system/src/Form/ModulesListForm.php +++ b/core/modules/system/src/Form/ModulesListForm.php @@ -80,11 +80,11 @@ public static function create(ContainerInterface $container) { return new static( $container->get('module_handler'), $container->get('module_installer'), + $container->get('extension.list.module'), $container->get('keyvalue.expirable')->get('module_list'), $container->get('access_manager'), $container->get('current_user'), - $container->get('user.permissions'), - $container->get('extension.list.module') + $container->get('user.permissions') ); } @@ -95,6 +95,8 @@ public static function create(ContainerInterface $container) { * The module handler. * @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer * The module installer. + * @param \Drupal\Core\Extension\ModuleExtensionList $extension_list_module + * The module extension list. * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable * The key value expirable factory. * @param \Drupal\Core\Access\AccessManagerInterface $access_manager @@ -104,14 +106,14 @@ public static function create(ContainerInterface $container) { * @param \Drupal\user\PermissionHandlerInterface $permission_handler * The permission handler. */ - public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable, AccessManagerInterface $access_manager, AccountInterface $current_user, PermissionHandlerInterface $permission_handler, ModuleExtensionList $extension_list_module) { + public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ModuleExtensionList $extension_list_module, KeyValueStoreExpirableInterface $key_value_expirable, AccessManagerInterface $access_manager, AccountInterface $current_user, PermissionHandlerInterface $permission_handler) { $this->moduleHandler = $module_handler; $this->moduleInstaller = $module_installer; + $this->moduleExtensionList = $extension_list_module; $this->keyValueExpirable = $key_value_expirable; $this->accessManager = $access_manager; $this->currentUser = $current_user; $this->permissionHandler = $permission_handler; - $this->moduleExtensionList = $extension_list_module; } /** @@ -153,7 +155,9 @@ public function buildForm(array $form, FormStateInterface $form_state) { ]; // Sort all modules by their names. - $modules = $this->moduleExtensionList->getList(); + // The module list needs to be reset so that it can re-scan and include any + // new modules that may have been added directly into the filesystem. + $modules = $this->moduleExtensionList->reset()->getList(); uasort($modules, 'system_sort_modules_by_info_name'); // Iterate over each of the modules. diff --git a/core/modules/system/src/Form/ModulesUninstallForm.php b/core/modules/system/src/Form/ModulesUninstallForm.php index 9fcefc3..bf3a06e 100644 --- a/core/modules/system/src/Form/ModulesUninstallForm.php +++ b/core/modules/system/src/Form/ModulesUninstallForm.php @@ -2,6 +2,7 @@ namespace Drupal\system\Form; +use Drupal\Core\Extension\ModuleExtensionList; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleInstallerInterface; use Drupal\Core\Form\FormBase; @@ -38,12 +39,20 @@ class ModulesUninstallForm extends FormBase { protected $keyValueExpirable; /** + * The module extension list. + * + * @var \Drupal\Core\Extension\ModuleExtensionList + */ + protected $moduleExtensionList; + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('module_handler'), $container->get('module_installer'), + $container->get('extension.list.module'), $container->get('keyvalue.expirable')->get('modules_uninstall') ); } @@ -55,12 +64,15 @@ public static function create(ContainerInterface $container) { * The module handler. * @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer * The module installer. + * @param \Drupal\Core\Extension\ModuleExtensionList $extension_list_module + * The module extension list. * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable * The key value expirable factory. */ - public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable) { + public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ModuleExtensionList $extension_list_module, KeyValueStoreExpirableInterface $key_value_expirable) { $this->moduleHandler = $module_handler; $this->moduleInstaller = $module_installer; + $this->moduleExtensionList = $extension_list_module; $this->keyValueExpirable = $key_value_expirable; } @@ -78,11 +90,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { // Make sure the install API is available. include_once DRUPAL_ROOT . '/core/includes/install.inc'; - // Get a list of all available modules. - $modules = \Drupal::service('extension.list.module')->getList(); - $uninstallable = array_filter($modules, function ($module) use ($modules) { - return empty($modules[$module->getName()]->info['required']) && $module->status; - }); + // Get a list of all available modules that can be uninstalled. + $uninstallable = array_filter($this->moduleExtensionList->getList(), + function ($module) { + return empty($module->info['required']) && $module->status; + }); // Include system.admin.inc so we can use the sort callbacks. $this->moduleHandler->loadInclude('system', 'inc', 'system.admin'); diff --git a/core/modules/update/src/UpdateManager.php b/core/modules/update/src/UpdateManager.php index bc1c491..fae499c 100644 --- a/core/modules/update/src/UpdateManager.php +++ b/core/modules/update/src/UpdateManager.php @@ -4,6 +4,7 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\DependencyInjection\DependencySerializationTrait; +use Drupal\Core\Extension\ModuleExtensionList; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; @@ -68,6 +69,13 @@ class UpdateManager implements UpdateManagerInterface { protected $themeHandler; /** + * The module extension list. + * + * @var \Drupal\Core\Extension\ModuleExtensionList + */ + protected $moduleExtensionList; + + /** * Constructs a UpdateManager. * * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory @@ -82,8 +90,10 @@ class UpdateManager implements UpdateManagerInterface { * The expirable key/value factory. * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler * The theme handler. + * @param \Drupal\Core\Extension\ModuleExtensionList $extension_list_module + * The module extension list. */ - public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, UpdateProcessorInterface $update_processor, TranslationInterface $translation, KeyValueFactoryInterface $key_value_expirable_factory, ThemeHandlerInterface $theme_handler) { + public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, UpdateProcessorInterface $update_processor, TranslationInterface $translation, KeyValueFactoryInterface $key_value_expirable_factory, ThemeHandlerInterface $theme_handler, ModuleExtensionList $extension_list_module = NULL) { $this->updateSettings = $config_factory->get('update.settings'); $this->moduleHandler = $module_handler; $this->updateProcessor = $update_processor; @@ -92,6 +102,7 @@ public function __construct(ConfigFactoryInterface $config_factory, ModuleHandle $this->themeHandler = $theme_handler; $this->availableReleasesTempStore = $key_value_expirable_factory->get('update_available_releases'); $this->projects = []; + $this->moduleExtensionList = $extension_list_module; } /** @@ -129,7 +140,7 @@ public function getProjects() { $this->projects = $this->projectStorage('update_project_projects'); if (empty($this->projects)) { // Still empty, so we have to rebuild. - $module_data = \Drupal::service('extension.list.module')->getList(); + $module_data = $this->getModuleExtensionList()->reset()->getList(); $theme_data = $this->themeHandler->rebuildThemeData(); $project_info = new ProjectInfo(); $project_info->processInfoList($this->projects, $module_data, 'module', TRUE); @@ -223,4 +234,16 @@ public function fetchDataBatch(&$context) { } } + /** + * Gets the module extension list. + * + * @return \Drupal\Core\Extension\ModuleExtensionList + */ + protected function getModuleExtensionList() { + if ($this->moduleExtensionList === NULL) { + $this->moduleExtensionList = \Drupal::service('extension.list.module'); + } + return $this->moduleExtensionList; + } + }