123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- <?php
- namespace Drupal\Core\Extension;
- use Drupal\Core\Cache\CacheBackendInterface;
- use Drupal\Core\Config\ConfigFactoryInterface;
- use Drupal\Core\State\StateInterface;
- use Drupal\Core\StringTranslation\StringTranslationTrait;
- /**
- * Provides a list of available modules.
- *
- * @internal
- * This class is not yet stable and therefore there are no guarantees that the
- * internal implementations including constructor signature and protected
- * properties / methods will not change over time. This will be reviewed after
- * https://www.drupal.org/project/drupal/issues/2940481
- */
- class ModuleExtensionList extends ExtensionList {
- use StringTranslationTrait;
- /**
- * {@inheritdoc}
- */
- protected $defaults = [
- 'dependencies' => [],
- 'description' => '',
- 'package' => 'Other',
- 'version' => NULL,
- 'php' => DRUPAL_MINIMUM_PHP,
- ];
- /**
- * The config factory.
- *
- * @var \Drupal\Core\Config\ConfigFactoryInterface
- */
- 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
- * The app root.
- * @param string $type
- * The extension type.
- * @param \Drupal\Core\Cache\CacheBackendInterface $cache
- * The cache.
- * @param \Drupal\Core\Extension\InfoParserInterface $info_parser
- * The info parser.
- * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
- * The module handler.
- * @param \Drupal\Core\State\StateInterface $state
- * The state.
- * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
- * The config factory.
- * @param \Drupal\Core\Extension\ExtensionList $profile_list
- * The site profile listing.
- * @param string $install_profile
- * The install profile used by the site.
- * @param array[] $container_modules_info
- * (optional) The module locations coming from the compiled container.
- */
- public function __construct($root, $type, CacheBackendInterface $cache, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler, StateInterface $state, ConfigFactoryInterface $config_factory, ExtensionList $profile_list, $install_profile, array $container_modules_info = []) {
- parent::__construct($root, $type, $cache, $info_parser, $module_handler, $state, $install_profile);
- $this->configFactory = $config_factory;
- $this->profileList = $profile_list;
- // Use the information from the container. This is an optimization.
- foreach ($container_modules_info as $module_name => $info) {
- $this->setPathname($module_name, $info['pathname']);
- }
- }
- /**
- * {@inheritdoc}
- */
- protected function getExtensionDiscovery() {
- $discovery = parent::getExtensionDiscovery();
- if ($active_profile = $this->getActiveProfile()) {
- $discovery->setProfileDirectories($this->getProfileDirectories($discovery));
- }
- return $discovery;
- }
- /**
- * Finds all installation profile paths.
- *
- * @param \Drupal\Core\Extension\ExtensionDiscovery $discovery
- * The extension discovery.
- *
- * @return string[]
- * Paths to all installation profiles.
- */
- protected function getProfileDirectories(ExtensionDiscovery $discovery) {
- $discovery->setProfileDirectories([]);
- $all_profiles = $discovery->scan('profile');
- $active_profile = $all_profiles[$this->installProfile];
- $profiles = array_intersect_key($all_profiles, $this->configFactory->get('core.extension')->get('module') ?: [$active_profile->getName() => 0]);
- $profile_directories = array_map(function (Extension $profile) {
- return $profile->getPath();
- }, $profiles);
- return $profile_directories;
- }
- /**
- * Gets the processed active profile object, or null.
- *
- * @return \Drupal\Core\Extension\Extension|null
- * The active profile, if there is one.
- */
- protected function getActiveProfile() {
- $profiles = $this->profileList->getList();
- if ($this->installProfile && isset($profiles[$this->installProfile])) {
- return $profiles[$this->installProfile];
- }
- return NULL;
- }
- /**
- * {@inheritdoc}
- */
- protected function doScanExtensions() {
- $extensions = parent::doScanExtensions();
- $profiles = $this->profileList->getList();
- // Modify the active profile object that was previously added to the module
- // list.
- if ($this->installProfile && isset($profiles[$this->installProfile])) {
- $extensions[$this->installProfile] = $profiles[$this->installProfile];
- }
- return $extensions;
- }
- /**
- * {@inheritdoc}
- */
- protected function doList() {
- // Find modules.
- $extensions = parent::doList();
- // 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->ensureRequiredDependencies($extension, $extensions);
- }
- // Add status, weight, and schema version.
- $installed_modules = $this->configFactory->get('core.extension')->get('module') ?: [];
- foreach ($extensions 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;
- }
- $extensions = $this->moduleHandler->buildModuleDependencies($extensions);
- if ($this->installProfile && $extensions[$this->installProfile]) {
- $active_profile = $extensions[$this->installProfile];
- // Installation profile hooks are always executed last.
- $active_profile->weight = 1000;
- // Installation profiles are hidden by default, unless explicitly
- // specified otherwise in the .info.yml file.
- if (!isset($active_profile->info['hidden'])) {
- $active_profile->info['hidden'] = TRUE;
- }
- // The installation profile is required.
- $active_profile->info['required'] = TRUE;
- // Add a default distribution name if the profile did not provide one.
- // @see install_profile_info()
- // @see drupal_install_profile_distribution_name()
- if (!isset($active_profile->info['distribution']['name'])) {
- $active_profile->info['distribution']['name'] = 'Drupal';
- }
- }
- return $extensions;
- }
- /**
- * {@inheritdoc}
- */
- protected function getInstalledExtensionNames() {
- return array_keys($this->moduleHandler->getModuleList());
- }
- /**
- * Marks dependencies of required modules as 'required', recursively.
- *
- * @param \Drupal\Core\Extension\Extension $module
- * The module extension object.
- * @param \Drupal\Core\Extension\Extension[] $modules
- * Extension objects for all available modules.
- */
- protected function ensureRequiredDependencies(Extension $module, array $modules = []) {
- if (!empty($module->info['required'])) {
- foreach ($module->info['dependencies'] as $dependency) {
- $dependency_name = Dependency::createFromString($dependency)->getName();
- if (!isset($modules[$dependency_name]->info['required'])) {
- $modules[$dependency_name]->info['required'] = TRUE;
- $modules[$dependency_name]->info['explanation'] = $this->t('Dependency of required module @module', ['@module' => $module->info['name']]);
- // Ensure any dependencies it has are required.
- $this->ensureRequiredDependencies($modules[$dependency_name], $modules);
- }
- }
- }
- }
- }
|