diff --git a/core/core.services.yml b/core/core.services.yml index d1a0e6c..8fb7a70 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -472,7 +472,10 @@ services: lazy: true module_listing: class: Drupal\Core\Extension\ModuleExtensionList - arguments: ['@app.root', 'module', '@cache.default', '@info_parser', '@module_handler', '@config.factory'] + arguments: ['@app.root', 'module', '@cache.default', '@info_parser', '@module_handler', '@state', '@config.factory', '@profile_listing'] + profile_listing: + class: Drupal\Core\Extension\ProfileExtensionList + arguments: ['@app.root', 'profile', '@cache.default', '@info_parser', '@module_handler', '@state'] content_uninstall_validator: class: Drupal\Core\Entity\ContentUninstallValidator tags: diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 5eeaf3c..3f59276 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -198,11 +198,17 @@ function drupal_get_filename($type, $name, $filename = NULL) { return 'core/core.info.yml'; } - // Profiles are converted into modules in system_rebuild_module_data(). - // @todo Remove false-exposure of profiles as modules. - if ($type == 'profile') { - $type = 'module'; + if ($type === 'module' || $type === 'profile') { + $service = $type . '_listing'; + if (isset($filename)) { + // Manually add the info file path of an extension. + return \Drupal::service($service)->setFilename($name); + } + else { + return \Drupal::service($service)->getFilename($name); + } } + if (!isset($files[$type])) { $files[$type] = array(); } @@ -211,15 +217,6 @@ function drupal_get_filename($type, $name, $filename = NULL) { $files[$type][$name] = $filename; } elseif (!isset($files[$type][$name])) { - // If the pathname of the requested extension is not known, try to retrieve - // the list of extension pathnames from various providers, checking faster - // providers first. - // Retrieve the current module list (derived from the service container). - if ($type == 'module' && \Drupal::hasService('module_handler')) { - foreach (\Drupal::moduleHandler()->getModuleList() as $module_name => $module) { - $files[$type][$module_name] = $module->getPathname(); - } - } // If still unknown, retrieve the file list prepared in state by // system_rebuild_module_data() and // \Drupal\Core\Extension\ThemeHandlerInterface::rebuildThemeData(). @@ -251,9 +248,6 @@ function drupal_get_filename($type, $name, $filename = NULL) { * The path to the requested item or an empty string if the item is not found. */ function drupal_get_path($type, $name) { - if ($type === 'module' || $type === 'profile') { - return dirname(\Drupal::service('module_listing')->getFilenames()[$name]); - } return dirname(drupal_get_filename($type, $name)); } diff --git a/core/includes/module.inc b/core/includes/module.inc index 027b236..cd2575c 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -57,7 +57,6 @@ 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 3e98d84..a0f9a7e 100644 --- a/core/lib/Drupal/Core/Extension/ExtensionList.php +++ b/core/lib/Drupal/Core/Extension/ExtensionList.php @@ -7,8 +7,9 @@ namespace Drupal\Core\Extension; -use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\State\StateInterface; /** * Provides available extensions. @@ -37,6 +38,11 @@ protected $cache; /** + * The state service. + */ + protected $state; + + /** * Default information added to every extension. * * @var array @@ -74,11 +80,28 @@ /** * A list of extension folder names keyed by extension name. * - * @var string + * @var string[] */ protected $fileNames; /** + * A list of extension folder names directly added in code (not discovered). + * + * It is important to keep a separate list to ensure that it takes priority + * over the discovered extension folder. + * + * @var string[] + */ + protected $addedFileNames; + + /** + * The extension discovery service. + * + * @var \Drupal\Core\Extension\ExtensionDiscovery + */ + protected $extensionDiscovery; + + /** * Constructs a new ExtensionList instance. * * @param string $root @@ -91,25 +114,30 @@ * The info parser. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. + * @param \Drupal\Core\State\StateInterface $state + * The state service. */ - public function __construct($root, $type, CacheBackendInterface $cache, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler) { + public function __construct($root, $type, CacheBackendInterface $cache, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler, StateInterface $state) { $this->root = $root; $this->type = $type; $this->cache = $cache; + $this->state = $state; $this->infoParser = $info_parser; $this->moduleHandler = $module_handler; + $this->extensionDiscovery = new ExtensionDiscovery($root); } /** * Resets the stored extension list. */ public function reset() { - $this->extensions = NULL; + $this->addedFileNames = NULL; $this->cache->delete($this->getCacheId()); $this->extensionInfo = NULL; $this->cache->delete("system.{$this->type}.info"); $this->fileNames = NULL; - \Drupal::state()->delete("system.{$this->type}.files"); + $this->state->delete("system.{$this->type}.files"); + $this->extensions = NULL; return $this; } @@ -125,18 +153,21 @@ protected function getCacheId() { /** * Returns the human readable name of the extension. * - * @param string $name + * @param string $machine_name * The extension name. * * @return string * The human readable name of the extension. + * + * @throws \InvalidArgumentException + * If there is no extension with the supplied machine name. */ - public function getName($name) { + public function getName($machine_name) { $extensions = $this->listExtensions(); - if (isset($extensions[$name])) { - return $extensions[$name]->info['name']; + if (isset($extensions[$machine_name])) { + return $extensions[$machine_name]->info['name']; } - throw new \InvalidArgumentException(SafeMarkup::format('The @type %name does not exist.', ['@type' => $this->type, '%name' => $name])); + throw new \InvalidArgumentException(new FormattableMarkup('The @type %name does not exist.', ['@type' => $this->type, '%name' => $machine_name])); } /** @@ -146,6 +177,9 @@ public function getName($name) { * The extension name. * * @return \Drupal\Core\Extension\Extension + * + * @throws \InvalidArgumentException + * If there is no extension with the supplied name. */ public function getExtension($name) { $extensions = $this->listExtensions(); @@ -153,7 +187,7 @@ public function getExtension($name) { return $extensions[$name]; } - throw new \InvalidArgumentException(SafeMarkup::format('The @type %name does not exist.', ['@type' => $this->type, '%name' => $name])); + throw new \InvalidArgumentException(new FormattableMarkup('The @type %name does not exist.', ['@type' => $this->type, '%name' => $name])); } /** @@ -181,13 +215,10 @@ public function listExtensions() { * Overriding this method gives other code the chance to add additional * extensions to this raw listing. * - * @param \Drupal\Core\Extension\ExtensionDiscovery $discovery - * The extension discovery. - * * @return \Drupal\Core\Extension\Extension[] */ - protected function doScanExtensions(ExtensionDiscovery $discovery) { - return $discovery->scan($this->type); + protected function doScanExtensions() { + return $this->extensionDiscovery->scan($this->type); } /** @@ -196,10 +227,8 @@ protected function doScanExtensions(ExtensionDiscovery $discovery) { * @return \Drupal\Core\Extension\Extension[] */ protected function doListExtensions() { - $listing = new ExtensionDiscovery($this->root); - // Find extensions. - $extensions = $this->doScanExtensions($listing); + $extensions = $this->doScanExtensions(); // Read info files for each extension. foreach ($extensions as $name => $extension) { @@ -215,7 +244,6 @@ protected function doListExtensions() { // Invoke hook_system_info_alter() to give installed modules a chance to // modify the data in the .info.yml files if necessary. - // @todo Remove $type argument, obsolete with $module->getType(). $this->moduleHandler->alter('system_info', $extensions[$name]->info, $extensions[$name], $this->type); } @@ -223,23 +251,36 @@ protected function doListExtensions() { } /** + * Returns information about a specified module or theme. + * + * This function returns the contents of the .info.yml file for the specified + * installed module or theme. + * + * @param string $name + * The name of a module or theme whose information shall be returned. If + * $name does not exist or is not enabled, an empty array will be returned. + * + * @return array|null + * An associative array of module or theme information. NULL if the module + * is disabled or does not exist. + */ + public function getInfo($name) { + // Ensure that $this->extensionInfo is primed. + $this->getAllInfo(); + return isset($this->extensionInfo[$name]) ? $this->extensionInfo[$name] : NULL; + } + + /** * Returns an array of information about enabled modules or themes. * * This function returns the contents of the .info.yml file for each installed * module or theme. * - * @param string $name - * (optional) The name of a module or theme whose information shall be - * returned. If omitted, all records for the provided $type will be returned. - * If $name does not exist in the provided $type or is not enabled, an empty - * array will be returned. - * * @return array - * An associative array of module or theme information keyed by name, or only - * information for $name, if given. If no records are available, an empty - * array is returned. + * An associative array of module or theme information keyed by name. If no + * records are available, an empty array is returned. */ - public function getInfo($name = NULL) { + public function getAllInfo() { if (!isset($this->extensionInfo)) { if ($cache = $this->cache->get("system.{$this->type}.info")) { $info = $cache->data; @@ -249,33 +290,36 @@ public function getInfo($name = NULL) { } $this->extensionInfo = $info; } - if (isset($name)) { - return isset($this->extensionInfo[$name]) ? $this->extensionInfo[$name] : []; - } return $this->extensionInfo; } + /** + * Generates the information from .info.yml files for extensions of this type. + * + * The information is placed in cache with the "system.{extension_type}.info" + * key. + * + * @return array + * An array of arrays of .info.yml entries keyed by the extension name. + */ protected function recalculateInfo() { $info = []; foreach ($this->listExtensions() as $name => $extension) { $info[$name] = $extension->info; } - // Store the module information in cache. This cache is cleared by - // calling system_rebuild_module_data(), for example, when listing - // modules, (un)installing modules, importing configuration, updating - // the site and when flushing all the caches. + // Store the module information in cache. $this->cache->set("system.{$this->type}.info", $info); return $info; } /** - * Return a list of extension folder names keyed by extension name. + * Returns a list of extension folder names keyed by extension name. * * @return string[] */ public function getFilenames() { if (!isset($this->fileNames)) { - $file_names = \Drupal::state()->get("system.{$this->type}.files"); + $file_names = $this->state->get("system.{$this->type}.files"); if (!isset($file_names)) { $file_names = $this->recalculateFilenames(); } @@ -284,6 +328,15 @@ public function getFilenames() { return $this->fileNames; } + /** + * Generates a sorted list of .info.yml file locations for all extensions. + * + * The information is placed in state with the "system.{extension_type}.files" + * key. + * + * @return array + * An array of .info.yml file locations keyed by the extension name. + */ protected function recalculateFilenames() { $file_names = []; $extensions = $this->listExtensions(); @@ -291,8 +344,78 @@ protected function recalculateFilenames() { foreach ($extensions as $name => $extension) { $file_names[$name] = $extension->getPathname(); } -// \Drupal::state()->set("system.{$this->type}.files", $file_names); + $this->state->set("system.{$this->type}.files", $file_names); return $file_names; } + /** + * Sets the filename for an extension. + * + * @param string $extension_name + * The name of the extension for which the filename is requested. + * @param string $filename + * The filename of the item which is to be set explicitly rather + * than by consulting the dynamic modules listing. + */ + public function setFilename($extension_name, $filename) { + $this->addedFileNames[$extension_name] = $filename; + } + + /** + * Gets the filename for a system resource. + * + * The filename, whether provided, cached, or retrieved from the database, is + * only returned if the file exists. + * + * This function plays a key role in allowing Drupal's resources (modules + * and themes) to be located in different places depending on a site's + * configuration. For example, a module 'foo' may legally be located + * in any of these three places: + * + * core/modules/foo/foo.info.yml + * modules/foo/foo.info.yml + * sites/example.com/modules/foo/foo.info.yml + * core/themes/foo/foo.info.yml + * themes/foo/foo.info.yml + * + * Calling ExtensionList::getFilename('foo') will give you one of the above, + * depending on where the extension is located and what type it is. + * + * @param string $extension_name + * The name of the item for which the filename is requested. Ignored for + * $type 'core'. + * + * @return string + * The filename of the requested item if it is found. An error is triggered + * if it is not. + */ + public function getFilename($extension_name) { + // Ensure that $this->fileNames is primed. + $this->getFilenames(); + if (isset($this->addedFileNames[$extension_name])) { + return $this->addedFileNames[$extension_name]; + } + else if (isset($this->fileNames[$extension_name])) { + return $this->fileNames[$extension_name]; + } + else { + trigger_error(new FormattableMarkup('The following @type is missing from the file system: @name', array('@type' => $this->type, '@name' => $extension_name)), E_USER_WARNING); + } + } + + + /** + * Gets the path to an extension of a specific type (module, theme, etc.). + * + * @param string $extension_name + * The name of the extension for which the path is requested. + * + * @return string + * The drupal root-relative path to the specified extension. An error is + * triggered if the extension is not found. + */ + public function getPath($extension_name) { + return dirname($this->getFilename($extension_name)); + } + } diff --git a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php index 9e7763e..e925aac 100644 --- a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php +++ b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\State\StateInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; /** @@ -37,6 +38,13 @@ class ModuleExtensionList extends ExtensionList { protected $configFactory; /** + * The profile list needed by this module list. + * + * @var \Drupal\Core\Extension\ExtensionList + */ + protected $profileList; + + /** * Constructs a new ModuleExtensionList instance. * * @param string $root @@ -49,23 +57,28 @@ class ModuleExtensionList extends ExtensionList { * The info parser. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. + * @param \Drupal\Core\State\StateInterface $state + * The state service. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. + * @param \Drupal\Core\Extension\ExtensionList $profile_list + * The site profile listing. */ - public function __construct($root, $type, CacheBackendInterface $cache, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) { - parent::__construct($root, $type, $cache, $info_parser, $module_handler); + public function __construct($root, $type, CacheBackendInterface $cache, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler, StateInterface $state, ConfigFactoryInterface $config_factory, ExtensionList $profile_list) { + parent::__construct($root, $type, $cache, $info_parser, $module_handler, $state); $this->configFactory = $config_factory; + $this->profileList = $profile_list; } /** * {@inheritdoc} */ - protected function doScanExtensions(ExtensionDiscovery $discovery) { - $extensions = parent::doScanExtensions($discovery); + protected function doScanExtensions() { + $extensions = parent::doScanExtensions(); // Find installation profiles. - $profiles = $discovery->scan('profile'); + $profiles = $this->profileList->listExtensions(); // Include the installation profile in modules that are loaded. if ($profile = drupal_get_profile()) { @@ -81,19 +94,16 @@ protected function doScanExtensions(ExtensionDiscovery $discovery) { * {@inheritdoc} */ protected function doListExtensions() { - $listing = new ExtensionDiscovery($this->root); - // Find installation profiles. This needs to happen before performing a - // module scan as the module scan requires knowing what the active profile is. - // @todo Remove as part of https://www.drupal.org/node/2186491 - $profiles = $listing->scan('profile'); + // module scan as the module scan needs to know what the active profile is. + $profiles = $this->profileList->listExtensions(); $profile = drupal_get_profile(); if ($profile && isset($profiles[$profile])) { - // Prime the drupal_get_filename() static cache with the profile info file - // location so we can use drupal_get_path() on the active profile during - // the module scan. - // @todo Remove as part of https://www.drupal.org/node/2186491 - drupal_get_filename('profile', $profile, $profiles[$profile]->getPathname()); + // Set the profile in the ExtensionDiscovery so we can scan from the right + // profile directory. + $this->extensionDiscovery->setProfileDirectories([ + $profile => $profiles[$profile]->getPathname(), + ]); } // Find modules. @@ -101,7 +111,7 @@ protected function doListExtensions() { // It is possible that a module was marked as required by // hook_system_info_alter() and modules that it depends on are not required. foreach ($extensions as $extension) { - $this->moduleDataEnsureRequired($extension, $extensions); + $this->ensureRequiredDependencies($extension, $extensions); } if ($profile) { @@ -143,7 +153,7 @@ protected function doListExtensions() { * @param \Drupal\Core\Extension\Extension[] $modules * The array of all module info. */ - protected function moduleDataEnsureRequired(Extension $module, array $modules = []) { + protected function ensureRequiredDependencies(Extension $module, array $modules = []) { if (!empty($module->info['required'])) { foreach ($module->info['dependencies'] as $dependency) { $dependency_name = ModuleHandler::parseDependency($dependency)['name']; @@ -151,7 +161,7 @@ protected function moduleDataEnsureRequired(Extension $module, array $modules = $modules[$dependency_name]->info['required'] = TRUE; $modules[$dependency_name]->info['explanation'] = $this->t('Dependency of required module @module', array('@module' => $module->info['name'])); // Ensure any dependencies it has are required. - $this->moduleDataEnsureRequired($modules[$dependency_name], $modules); + $this->ensureRequiredDependencies($modules[$dependency_name], $modules); } } } diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index 9c652ba..36e8ed8 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -190,7 +190,7 @@ public function install(array $module_list, $enable_dependencies = TRUE) { // Clear the static cache of system_rebuild_module_data() to pick up the // new module, since it merges the installation status of modules into // its statically cached list. - drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); // Update the kernel to include it. $this->updateKernel($module_filenames); @@ -426,10 +426,10 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { // Remove any potential cache bins provided by the module. $this->removeCacheBins($module); - // Clear the static cache of system_rebuild_module_data() to pick up the + // Clear the static cache of ModuleExtensionList to pick up the // new module, since it merges the installation status of modules into // its statically cached list. - drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); // Clear plugin manager caches. \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); diff --git a/core/lib/Drupal/Core/Extension/ProfileExtensionList.php b/core/lib/Drupal/Core/Extension/ProfileExtensionList.php new file mode 100644 index 0000000..8bae168 --- /dev/null +++ b/core/lib/Drupal/Core/Extension/ProfileExtensionList.php @@ -0,0 +1,18 @@ + [], + 'description' => '', + 'package' => 'Other', + 'version' => NULL, + 'php' => DRUPAL_MINIMUM_PHP, + ]; + +} diff --git a/core/modules/book/src/Tests/BookUninstallTest.php b/core/modules/book/src/Tests/BookUninstallTest.php index b46901e..45dac11 100644 --- a/core/modules/book/src/Tests/BookUninstallTest.php +++ b/core/modules/book/src/Tests/BookUninstallTest.php @@ -81,11 +81,7 @@ public function testBookUninstall() { $book_node->delete(); // No nodes exist therefore the book module is not required. - $module_data = _system_rebuild_module_data(); - /** @var \Drupal\Core\Extension\ModuleExtensionList $module_listing */ - $module_listing = \Drupal::service('module_listing'); - $module_listing->reset(); - $module_data = $module_listing->listExtensions(); + $module_data = \Drupal::service('module_listing')->reset()->listExtensions(); $this->assertFalse(isset($module_data['book']->info['required']), 'The book module is not required.'); $node = Node::create(array('title' => $this->randomString(), 'type' => $content_type->id())); diff --git a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php index 27ca162..dc6763a 100644 --- a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php +++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php @@ -26,8 +26,6 @@ function testDrupalGetFilename() { $install_state['parameters']['profile'] = 'testing'; // Rebuild system.module.files state data. - // @todo Remove as part of https://www.drupal.org/node/2186491 - drupal_static_reset('system_rebuild_module_data'); system_rebuild_module_data(); // Retrieving the location of a module. diff --git a/core/modules/system/system.module b/core/modules/system/system.module index e7c61ab..9e541c4 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -888,9 +888,7 @@ function system_check_directory($form_element, FormStateInterface $form_state) { */ function system_get_info($type, $name = NULL) { if ($type == 'module') { - /** @var \Drupal\Core\Extension\ModuleExtensionList $module_listing */ - $module_listing = \Drupal::service('module_listing'); - return $module_listing->getInfo($name); + return \Drupal::service('module_listing')->getInfo($name); } else { // @todo @@ -915,8 +913,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(); + return \Drupal::service('module_listing')->reset()->listExtensions(); } /** @@ -926,9 +923,7 @@ function _system_rebuild_module_data() { * Array of all available modules and their data. */ function system_rebuild_module_data() { - \Drupal::service('module_listing')->reset(); - $modules_cache = \Drupal::service('module_listing')->listExtensions(); - return $modules_cache; + return \Drupal::service('module_listing')->reset()->listExtensions(); } /** diff --git a/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php b/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php index 1dd99cd..413f912 100644 --- a/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php +++ b/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php @@ -119,7 +119,6 @@ function testDependencyResolution() { // Color will depend on Config, which depends on a non-existing module Foo. // 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 { @@ -135,7 +134,6 @@ function testDependencyResolution() { // Fix the missing dependency. // 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')); @@ -168,7 +166,6 @@ function testDependencyResolution() { // dependency on a specific version of Help module in its info file. Make // 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')); @@ -199,8 +196,7 @@ function testUninstallProfileDependency() { drupal_get_filename('profile', $profile, 'core/profiles/' . $profile . '/' . $profile . '.info.yml'); $this->enableModules(array('module_test', $profile)); - drupal_static_reset('system_rebuild_module_data'); - $data = system_rebuild_module_data(); + $data = \Drupal::service('module_listing')->reset()->listExtensions(); $this->assertTrue(isset($data[$profile]->requires[$dependency])); $this->moduleInstaller()->install(array($dependency)); @@ -238,7 +234,7 @@ function testUninstallContentDependency() { // entity_test will depend on help. This way help can not be uninstalled // when there is test content preventing entity_test from being uninstalled. \Drupal::state()->set('module_test.dependency', 'dependency'); - drupal_static_reset('system_rebuild_module_data'); + \Drupal::service('module_listing')->reset(); // Create an entity so that the modules can not be disabled. $entity = entity_create('entity_test', array('name' => $this->randomString()));