Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 260 |
| ModulesListForm | |
0.00% |
0 / 1 |
|
0.00% |
0 / 7 |
3422 | |
0.00% |
0 / 260 |
| create | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 9 |
|||
| __construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 7 |
|||
| getFormId | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| buildForm | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 54 |
|||
| buildRow | |
0.00% |
0 / 1 |
812 | |
0.00% |
0 / 110 |
|||
| buildModuleList | |
0.00% |
0 / 1 |
240 | |
0.00% |
0 / 38 |
|||
| submitForm | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 40 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\system\Form\ModulesListForm. | |
| */ | |
| namespace Drupal\system\Form; | |
| use Drupal\Component\Utility\Unicode; | |
| use Drupal\Core\Config\PreExistingConfigException; | |
| use Drupal\Core\Config\UnmetDependenciesException; | |
| use Drupal\Core\Access\AccessManagerInterface; | |
| use Drupal\Core\Extension\Extension; | |
| use Drupal\Core\Extension\ModuleHandlerInterface; | |
| use Drupal\Core\Extension\ModuleInstallerInterface; | |
| use Drupal\Core\Form\FormBase; | |
| use Drupal\Core\Form\FormStateInterface; | |
| use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface; | |
| use Drupal\Core\Render\Element; | |
| use Drupal\Core\Session\AccountInterface; | |
| use Drupal\user\PermissionHandlerInterface; | |
| use Drupal\Core\Url; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| /** | |
| * Provides module installation interface. | |
| * | |
| * The list of modules gets populated by module.info.yml files, which contain | |
| * each module's name, description, and information about which modules it | |
| * requires. See \Drupal\Core\Extension\InfoParser for info on module.info.yml | |
| * descriptors. | |
| */ | |
| class ModulesListForm extends FormBase { | |
| /** | |
| * The current user. | |
| * | |
| * @var \Drupal\Core\Session\AccountInterface | |
| */ | |
| protected $currentUser; | |
| /** | |
| * The module handler service. | |
| * | |
| * @var \Drupal\Core\Extension\ModuleHandlerInterface | |
| */ | |
| protected $moduleHandler; | |
| /** | |
| * The expirable key value store. | |
| * | |
| * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface | |
| */ | |
| protected $keyValueExpirable; | |
| /** | |
| * The module installer. | |
| * | |
| * @var \Drupal\Core\Extension\ModuleInstallerInterface | |
| */ | |
| protected $moduleInstaller; | |
| /** | |
| * The permission handler. | |
| * | |
| * @var \Drupal\user\PermissionHandlerInterface | |
| */ | |
| protected $permissionHandler; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public static function create(ContainerInterface $container) { | |
| return new static( | |
| $container->get('module_handler'), | |
| $container->get('module_installer'), | |
| $container->get('keyvalue.expirable')->get('module_list'), | |
| $container->get('access_manager'), | |
| $container->get('current_user'), | |
| $container->get('user.permissions') | |
| ); | |
| } | |
| /** | |
| * Constructs a ModulesListForm object. | |
| * | |
| * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
| * The module handler. | |
| * @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer | |
| * The module installer. | |
| * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable | |
| * The key value expirable factory. | |
| * @param \Drupal\Core\Access\AccessManagerInterface $access_manager | |
| * Access manager. | |
| * @param \Drupal\Core\Session\AccountInterface $current_user | |
| * The current user. | |
| * @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) { | |
| $this->moduleHandler = $module_handler; | |
| $this->moduleInstaller = $module_installer; | |
| $this->keyValueExpirable = $key_value_expirable; | |
| $this->accessManager = $access_manager; | |
| $this->currentUser = $current_user; | |
| $this->permissionHandler = $permission_handler; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getFormId() { | |
| return 'system_modules'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function buildForm(array $form, FormStateInterface $form_state) { | |
| require_once DRUPAL_ROOT . '/core/includes/install.inc'; | |
| $distribution = drupal_install_profile_distribution_name(); | |
| // Include system.admin.inc so we can use the sort callbacks. | |
| $this->moduleHandler->loadInclude('system', 'inc', 'system.admin'); | |
| $form['filters'] = array( | |
| '#type' => 'container', | |
| '#attributes' => array( | |
| 'class' => array('table-filter', 'js-show'), | |
| ), | |
| ); | |
| $form['filters']['text'] = array( | |
| '#type' => 'search', | |
| '#title' => $this->t('Filter modules'), | |
| '#title_display' => 'invisible', | |
| '#size' => 30, | |
| '#placeholder' => $this->t('Filter by name or description'), | |
| '#description' => $this->t('Enter a part of the module name or description'), | |
| '#attributes' => array( | |
| 'class' => array('table-filter-text'), | |
| 'data-table' => '#system-modules', | |
| 'autocomplete' => 'off', | |
| ), | |
| ); | |
| // Sort all modules by their names. | |
| $modules = system_rebuild_module_data(); | |
| uasort($modules, 'system_sort_modules_by_info_name'); | |
| // Iterate over each of the modules. | |
| $form['modules']['#tree'] = TRUE; | |
| foreach ($modules as $filename => $module) { | |
| if (empty($module->info['hidden'])) { | |
| $package = $module->info['package']; | |
| $form['modules'][$package][$filename] = $this->buildRow($modules, $module, $distribution); | |
| } | |
| } | |
| // Add a wrapper around every package. | |
| foreach (Element::children($form['modules']) as $package) { | |
| $form['modules'][$package] += array( | |
| '#type' => 'details', | |
| '#title' => $this->t($package), | |
| '#open' => TRUE, | |
| '#theme' => 'system_modules_details', | |
| '#attributes' => array('class' => array('package-listing')), | |
| // Ensure that the "Core" package comes first. | |
| '#weight' => $package == 'Core' ? -10 : NULL, | |
| ); | |
| } | |
| // If testing modules are shown, collapse the corresponding package by | |
| // default. | |
| if (isset($form['modules']['Testing'])) { | |
| $form['modules']['Testing']['#open'] = FALSE; | |
| } | |
| // Lastly, sort all packages by title. | |
| uasort($form['modules'], array('\Drupal\Component\Utility\SortArray', 'sortByTitleProperty')); | |
| $form['#attached']['library'][] = 'system/drupal.system.modules'; | |
| $form['actions'] = array('#type' => 'actions'); | |
| $form['actions']['submit'] = array( | |
| '#type' => 'submit', | |
| '#value' => $this->t('Install'), | |
| '#button_type' => 'primary', | |
| ); | |
| return $form; | |
| } | |
| /** | |
| * Builds a table row for the system modules page. | |
| * | |
| * @param array $modules | |
| * The list existing modules. | |
| * @param \Drupal\Core\Extension\Extension $module | |
| * The module for which to build the form row. | |
| * @param $distribution | |
| * | |
| * @return array | |
| * The form row for the given module. | |
| */ | |
| protected function buildRow(array $modules, Extension $module, $distribution) { | |
| // Set the basic properties. | |
| $row['#required'] = array(); | |
| $row['#requires'] = array(); | |
| $row['#required_by'] = array(); | |
| $row['name']['#markup'] = $module->info['name']; | |
| $row['description']['#markup'] = $this->t($module->info['description']); | |
| $row['version']['#markup'] = $module->info['version']; | |
| // Generate link for module's help page. Assume that if a hook_help() | |
| // implementation exists then the module provides an overview page, rather | |
| // than checking to see if the page exists, which is costly. | |
| if ($this->moduleHandler->moduleExists('help') && $module->status && in_array($module->getName(), $this->moduleHandler->getImplementations('help'))) { | |
| $row['links']['help'] = array( | |
| '#type' => 'link', | |
| '#title' => $this->t('Help'), | |
| '#url' => Url::fromRoute('help.page', ['name' => $module->getName()]), | |
| '#options' => array('attributes' => array('class' => array('module-link', 'module-link-help'), 'title' => $this->t('Help'))), | |
| ); | |
| } | |
| // Generate link for module's permission, if the user has access to it. | |
| if ($module->status && $this->currentUser->hasPermission('administer permissions') && $this->permissionHandler->moduleProvidesPermissions($module->getName())) { | |
| $row['links']['permissions'] = array( | |
| '#type' => 'link', | |
| '#title' => $this->t('Permissions'), | |
| '#url' => Url::fromRoute('user.admin_permissions'), | |
| '#options' => array('fragment' => 'module-' . $module->getName(), 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => $this->t('Configure permissions'))), | |
| ); | |
| } | |
| // Generate link for module's configuration page, if it has one. | |
| if ($module->status && isset($module->info['configure'])) { | |
| $route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array(); | |
| if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) { | |
| $row['links']['configure'] = array( | |
| '#type' => 'link', | |
| '#title' => $this->t('Configure <span class="visually-hidden">the @module module</span>', ['@module' => $module->info['name']]), | |
| '#url' => Url::fromRoute($module->info['configure'], $route_parameters), | |
| '#options' => array( | |
| 'attributes' => array( | |
| 'class' => array('module-link', 'module-link-configure'), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| // Present a checkbox for installing and indicating the status of a module. | |
| $row['enable'] = array( | |
| '#type' => 'checkbox', | |
| '#title' => $this->t('Install'), | |
| '#default_value' => (bool) $module->status, | |
| '#disabled' => (bool) $module->status, | |
| ); | |
| // Disable the checkbox for required modules. | |
| if (!empty($module->info['required'])) { | |
| // Used when displaying modules that are required by the installation profile | |
| $row['enable']['#disabled'] = TRUE; | |
| $row['#required_by'][] = $distribution . (!empty($module->info['explanation']) ? ' ('. $module->info['explanation'] .')' : ''); | |
| } | |
| // Check the compatibilities. | |
| $compatible = TRUE; | |
| // Initialize an empty array of reasons why the module is incompatible. Add | |
| // each reason as a separate element of the array. | |
| $reasons = array(); | |
| // Check the core compatibility. | |
| if ($module->info['core'] != \Drupal::CORE_COMPATIBILITY) { | |
| $compatible = FALSE; | |
| $reasons[] = $this->t('This version is not compatible with Drupal @core_version and should be replaced.', array( | |
| '@core_version' => \Drupal::CORE_COMPATIBILITY, | |
| )); | |
| } | |
| // Ensure this module is compatible with the currently installed version of PHP. | |
| if (version_compare(phpversion(), $module->info['php']) < 0) { | |
| $compatible = FALSE; | |
| $required = $module->info['php'] . (substr_count($module->info['php'], '.') < 2 ? '.*' : ''); | |
| $reasons[] = $this->t('This module requires PHP version @php_required and is incompatible with PHP version @php_version.', array( | |
| '@php_required' => $required, | |
| '@php_version' => phpversion(), | |
| )); | |
| } | |
| // If this module is not compatible, disable the checkbox. | |
| if (!$compatible) { | |
| $status = implode(' ', $reasons); | |
| $row['enable']['#disabled'] = TRUE; | |
| $row['description']['#markup'] = $status; | |
| $row['#attributes']['class'][] = 'incompatible'; | |
| } | |
| // If this module requires other modules, add them to the array. | |
| foreach ($module->requires as $dependency => $version) { | |
| if (!isset($modules[$dependency])) { | |
| $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">missing</span>)', array('@module' => Unicode::ucfirst($dependency))); | |
| $row['enable']['#disabled'] = TRUE; | |
| } | |
| // Only display visible modules. | |
| elseif (empty($modules[$dependency]->hidden)) { | |
| $name = $modules[$dependency]->info['name']; | |
| // Disable the module's checkbox if it is incompatible with the | |
| // dependency's version. | |
| if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) { | |
| $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> version @version)', array( | |
| '@module' => $name . $incompatible_version, | |
| '@version' => $modules[$dependency]->info['version'], | |
| )); | |
| $row['enable']['#disabled'] = TRUE; | |
| } | |
| // Disable the checkbox if the dependency is incompatible with this | |
| // version of Drupal core. | |
| elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) { | |
| $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array( | |
| '@module' => $name, | |
| )); | |
| $row['enable']['#disabled'] = TRUE; | |
| } | |
| elseif ($modules[$dependency]->status) { | |
| $row['#requires'][$dependency] = $this->t('@module', array('@module' => $name)); | |
| } | |
| else { | |
| $row['#requires'][$dependency] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $name)); | |
| } | |
| } | |
| } | |
| // If this module is required by other modules, list those, and then make it | |
| // impossible to disable this one. | |
| foreach ($module->required_by as $dependent => $version) { | |
| if (isset($modules[$dependent]) && empty($modules[$dependent]->info['hidden'])) { | |
| if ($modules[$dependent]->status == 1 && $module->status == 1) { | |
| $row['#required_by'][$dependent] = $this->t('@module', array('@module' => $modules[$dependent]->info['name'])); | |
| $row['enable']['#disabled'] = TRUE; | |
| } | |
| else { | |
| $row['#required_by'][$dependent] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $modules[$dependent]->info['name'])); | |
| } | |
| } | |
| } | |
| return $row; | |
| } | |
| /** | |
| * Helper function for building a list of modules to install. | |
| * | |
| * @param \Drupal\Core\Form\FormStateInterface $form_state | |
| * The current state of the form. | |
| * | |
| * @return array | |
| * An array of modules to install and their dependencies. | |
| */ | |
| protected function buildModuleList(FormStateInterface $form_state) { | |
| $packages = $form_state->getValue('modules'); | |
| // Build a list of modules to install. | |
| $modules = array( | |
| 'install' => array(), | |
| 'dependencies' => array(), | |
| ); | |
| // Required modules have to be installed. | |
| // @todo This should really not be handled here. | |
| $data = system_rebuild_module_data(); | |
| foreach ($data as $name => $module) { | |
| if (!empty($module->required) && !$this->moduleHandler->moduleExists($name)) { | |
| $modules['install'][$name] = $module->info['name']; | |
| } | |
| } | |
| // First, build a list of all modules that were selected. | |
| foreach ($packages as $items) { | |
| foreach ($items as $name => $checkbox) { | |
| if ($checkbox['enable'] && !$this->moduleHandler->moduleExists($name)) { | |
| $modules['install'][$name] = $data[$name]->info['name']; | |
| } | |
| } | |
| } | |
| // Add all dependencies to a list. | |
| while (list($module) = each($modules['install'])) { | |
| foreach (array_keys($data[$module]->requires) as $dependency) { | |
| if (!isset($modules['install'][$dependency]) && !$this->moduleHandler->moduleExists($dependency)) { | |
| $modules['dependencies'][$module][$dependency] = $data[$dependency]->info['name']; | |
| $modules['install'][$dependency] = $data[$dependency]->info['name']; | |
| } | |
| } | |
| } | |
| // Make sure the install API is available. | |
| include_once DRUPAL_ROOT . '/core/includes/install.inc'; | |
| // Invoke hook_requirements('install'). If failures are detected, make | |
| // sure the dependent modules aren't installed either. | |
| foreach (array_keys($modules['install']) as $module) { | |
| if (!drupal_check_module($module)) { | |
| unset($modules['install'][$module]); | |
| foreach (array_keys($data[$module]->required_by) as $dependent) { | |
| unset($modules['install'][$dependent]); | |
| unset($modules['dependencies'][$dependent]); | |
| } | |
| } | |
| } | |
| return $modules; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function submitForm(array &$form, FormStateInterface $form_state) { | |
| // Retrieve a list of modules to install and their dependencies. | |
| $modules = $this->buildModuleList($form_state); | |
| // Check if we have to install any dependencies. If there is one or more | |
| // dependencies that are not installed yet, redirect to the confirmation | |
| // form. | |
| if (!empty($modules['dependencies']) || !empty($modules['missing'])) { | |
| // Write the list of changed module states into a key value store. | |
| $account = $this->currentUser()->id(); | |
| $this->keyValueExpirable->setWithExpire($account, $modules, 60); | |
| // Redirect to the confirmation form. | |
| $form_state->setRedirect('system.modules_list_confirm'); | |
| // We can exit here because at least one modules has dependencies | |
| // which we have to prompt the user for in a confirmation form. | |
| return; | |
| } | |
| // Install the given modules. | |
| if (!empty($modules['install'])) { | |
| try { | |
| $this->moduleInstaller->install(array_keys($modules['install'])); | |
| $module_names = array_values($modules['install']); | |
| drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', array( | |
| '%name' => $module_names[0], | |
| '%names' => implode(', ', $module_names), | |
| ))); | |
| } | |
| catch (PreExistingConfigException $e) { | |
| $config_objects = $e->flattenConfigObjects($e->getConfigObjects()); | |
| drupal_set_message( | |
| $this->formatPlural( | |
| count($config_objects), | |
| 'Unable to install @extension, %config_names already exists in active configuration.', | |
| 'Unable to install @extension, %config_names already exist in active configuration.', | |
| array( | |
| '%config_names' => implode(', ', $config_objects), | |
| '@extension' => $modules['install'][$e->getExtension()] | |
| )), | |
| 'error' | |
| ); | |
| return; | |
| } | |
| catch (UnmetDependenciesException $e) { | |
| drupal_set_message( | |
| $e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()]), | |
| 'error' | |
| ); | |
| return; | |
| } | |
| } | |
| } | |
| } |