diff --git a/core/core.services.yml b/core/core.services.yml index bfa5aca..6d936d2 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -416,7 +416,7 @@ services: lazy: true module_listing: class: Drupal\Core\Extension\ModuleExtensionList - arguments: ['@app.root', 'module', '@state', '@info_parser', '@module_handler'] + arguments: ['@app.root', 'module', '@state', '@info_parser', '@module_handler', '@config.factory'] content_uninstall_validator: class: Drupal\Core\Entity\ContentUninstallValidator tags: diff --git a/core/includes/module.inc b/core/includes/module.inc index f65f0b8..84f9125 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -59,6 +59,7 @@ function system_list($type) { function system_list_reset() { drupal_static_reset('system_list'); drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); \Drupal::cache('bootstrap')->delete('system_list'); } diff --git a/core/lib/Drupal/Core/Extension/ExtensionList.php b/core/lib/Drupal/Core/Extension/ExtensionList.php index 8b3b47f..2e5aeae 100644 --- a/core/lib/Drupal/Core/Extension/ExtensionList.php +++ b/core/lib/Drupal/Core/Extension/ExtensionList.php @@ -56,6 +56,13 @@ class ExtensionList { protected $moduleHandler; /** + * The static cached extensions. + * + * @var \Drupal\Core\Extension\Extension[] + */ + protected $extensions; + + /** * Constructs a new ExtensionList instance. * * @param string $root @@ -77,6 +84,20 @@ public function __construct($root, $type, StateInterface $state, InfoParserInter $this->moduleHandler = $module_handler; } + public function reset() { + $this->extensions = NULL; + $this->state->delete($this->getStateKey()); + } + + /** + * Returns the used state key. + * + * @return string + */ + protected function getStateKey() { + return 'core.extension_listing.' . $this->type; + } + /** * Returns the human readable name of the extension. * @@ -95,6 +116,19 @@ public function getName($name) { } /** + * Returns a single extension. + * + * @param string $name + * The extension name. + * + * @return \Drupal\Core\Extension\Extension + */ + public function getExtension($name) { + $extensions = $this->listExtensions(); + return $extensions[$name]; + } + + /** * Returns all available extensions. * * @return \Drupal\Core\Extension\Extension[] @@ -103,11 +137,11 @@ public function listExtensions() { if (isset($this->extensions)) { return $this->extensions; } - if ($extensions = $this->state->get('core.extension_listing.' . $this->type)) { + if ($extensions = $this->state->get($this->getStateKey())) { return $extensions; } $extensions = $this->doListExtensions(); - $this->state->get('core.extension_listing.' . $this->type); + $this->state->get($this->getStateKey()); $this->extensions = $extensions; return $this->extensions; } diff --git a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php index 10570ee..39f21cd 100644 --- a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php +++ b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php @@ -7,6 +7,9 @@ namespace Drupal\Core\Extension; +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\State\StateInterface; + class ModuleExtensionList extends ExtensionList { protected $defaults = [ @@ -18,6 +21,36 @@ class ModuleExtensionList extends ExtensionList { ]; /** + * The config factory. + * + * @var \Drupal\Core\Config\ConfigFactoryInterface + */ + protected $configFactory; + + /** + * Constructs a new ModuleExtensionList instance. + * + * @param string $root + * The app root. + * @param string $type + * The extension type. + * @param \Drupal\Core\State\StateInterface $state + * The state. + * @param \Drupal\Core\Extension\InfoParserInterface $info_parser + * The info parser + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory + * The config factory. + */ + public function __construct($root, $type, StateInterface $state, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) { + parent::__construct($root, $type, $state, $info_parser, $module_handler); + + $this->configFactory = $config_factory; + } + + + /** * {@inheritdoc} */ protected function doScanExtensions(ExtensionDiscovery $discovery) { @@ -67,6 +100,16 @@ protected function doListExtensions() { $this->moduleDataEnsureRequired($extension, $extensions); } + // Add status, weight, and schema version. + $installed_modules = \Drupal::config('core.extension')->get('module') ?: array(); + foreach ($extensions as $name => $extension) { + $extension->weight = isset($installed_modules[$name]) ? $installed_modules[$name] : 0; + $extension->status = (int) isset($installed_modules[$name]); + $extension->schema_version = SCHEMA_UNINSTALLED; + $files[$name] = $extension->getPathname(); + } + $extensions = $this->moduleHandler->buildModuleDependencies($extensions); + return $extensions; } diff --git a/core/modules/book/src/Tests/BookUninstallTest.php b/core/modules/book/src/Tests/BookUninstallTest.php index 317a16a..ab7e065 100644 --- a/core/modules/book/src/Tests/BookUninstallTest.php +++ b/core/modules/book/src/Tests/BookUninstallTest.php @@ -44,7 +44,8 @@ protected function setUp() { */ public function testBookUninstall() { // No nodes exist. - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertFalse(isset($module_data['book']->info['required']), 'The book module is not required.'); $content_type = NodeType::create(array( @@ -62,7 +63,8 @@ public function testBookUninstall() { $node->save(); // One node in a book but not of type book. - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertTrue($module_data['book']->info['required'], 'The book module is required.'); $this->assertEqual($module_data['book']->info['explanation'], t('To uninstall Book, delete all content that is part of a book.')); @@ -72,26 +74,30 @@ public function testBookUninstall() { // Two nodes, one in a book but not of type book and one book node (which is // not in a book). - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertTrue($module_data['book']->info['required'], 'The book module is required.'); $this->assertEqual($module_data['book']->info['explanation'], t('To uninstall Book, delete all content that is part of a book.')); $node->delete(); // One node of type book but not actually part of a book. - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertTrue($module_data['book']->info['required'], 'The book module is required.'); $this->assertEqual($module_data['book']->info['explanation'], t('To uninstall Book, delete all content that has the Book content type.')); $book_node->delete(); // No nodes exist therefore the book module is not required. - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertFalse(isset($module_data['book']->info['required']), 'The book module is not required.'); $node = Node::create(array('type' => $content_type->id())); $node->save(); // One node exists but is not part of a book therefore the book module is // not required. - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertFalse(isset($module_data['book']->info['required']), 'The book module is not required.'); // Uninstall the Book module and check the node type is deleted. diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php index 49b99d2..0386e7d 100644 --- a/core/modules/filter/src/Tests/FilterAPITest.php +++ b/core/modules/filter/src/Tests/FilterAPITest.php @@ -424,7 +424,8 @@ public function testDependencyRemoval() { ]; $filter_format->setFilterConfig('filter_test_restrict_tags_and_attributes', $filter_config)->save(); - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertTrue($module_data['filter_test']->info['required'], 'The filter_test module is required.'); $this->assertEqual($module_data['filter_test']->info['explanation'], SafeMarkup::format('Provides a filter plugin that is in use in the following filter formats: %formats', array('%formats' => $filter_format->label()))); @@ -443,7 +444,8 @@ public function testDependencyRemoval() { drupal_static_reset('filter_formats'); \Drupal::entityManager()->getStorage('filter_format')->resetCache(); - $module_data = _system_rebuild_module_data(); + \Drupal::service('module_listing')->reset(); + $module_data = \Drupal::service('module_listing')->listExtensions(); $this->assertFalse(isset($module_data['filter_test']->info['required']), 'The filter_test module is required.'); // Verify that a dependency exists on the module that provides the filter diff --git a/core/modules/system/src/Tests/Extension/ModuleHandlerTest.php b/core/modules/system/src/Tests/Extension/ModuleHandlerTest.php index d2d6fed..edaf2a0 100644 --- a/core/modules/system/src/Tests/Extension/ModuleHandlerTest.php +++ b/core/modules/system/src/Tests/Extension/ModuleHandlerTest.php @@ -115,6 +115,7 @@ function testDependencyResolution() { // Nothing should be installed. \Drupal::state()->set('module_test.dependency', 'missing dependency'); drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); try { $result = $this->moduleInstaller()->install(array('color')); @@ -130,6 +131,7 @@ function testDependencyResolution() { // Color module depends on Config. Config depends on Help module. \Drupal::state()->set('module_test.dependency', 'dependency'); drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); $result = $this->moduleInstaller()->install(array('color')); $this->assertTrue($result, 'ModuleHandler::install() returns the correct value.'); @@ -162,6 +164,7 @@ function testDependencyResolution() { // sure that Drupal\Core\Extension\ModuleHandler::install() still works. \Drupal::state()->set('module_test.dependency', 'version dependency'); drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); $result = $this->moduleInstaller()->install(array('color')); $this->assertTrue($result, 'ModuleHandler::install() returns the correct value.'); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 93e4772..6ff08e8 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -882,6 +882,7 @@ function system_get_info($type, $name = NULL) { * An associative array of module information. */ function _system_rebuild_module_data() { + \Drupal::service('module_listing')->reset(); return \Drupal::service('module_listing')->listExtensions(); } @@ -892,30 +893,7 @@ function _system_rebuild_module_data() { * Array of all available modules and their data. */ function system_rebuild_module_data() { - $modules_cache = &drupal_static(__FUNCTION__); - // Only rebuild once per request. $modules and $modules_cache cannot be - // combined into one variable, because the $modules_cache variable is reset by - // reference from system_list_reset() during the rebuild. - if (!isset($modules_cache)) { - $modules = _system_rebuild_module_data(); - $files = array(); - ksort($modules); - // Add status, weight, and schema version. - $installed_modules = \Drupal::config('core.extension')->get('module') ?: array(); - foreach ($modules as $name => $module) { - $module->weight = isset($installed_modules[$name]) ? $installed_modules[$name] : 0; - $module->status = (int) isset($installed_modules[$name]); - $module->schema_version = SCHEMA_UNINSTALLED; - $files[$name] = $module->getPathname(); - } - $modules = \Drupal::moduleHandler()->buildModuleDependencies($modules); - $modules_cache = $modules; - - // Store filenames to allow system_list() and drupal_get_filename() to - // retrieve them without having to rebuild or scan the filesystem. - \Drupal::state()->set('system.module.files', $files); - } - return $modules_cache; + return \Drupal::service('module_listing')->listExtensions(); } /**