Commit 8d693ade authored by alexpott's avatar alexpott
Browse files

Issue #1990544 by fubhy, Pancho, h3rj4n, dawehner: Convert system_modules() to a Controller.

parent 862b4d63
......@@ -114,6 +114,19 @@ public static function open(array &$connection_options = array()) {
return $pdo;
}
/**
* {@inheritdoc}
*/
public function serialize() {
// Cleanup the connection, much like __destruct() does it as well.
if ($this->needsCleanup) {
$this->nextIdDelete();
}
$this->needsCleanup = FALSE;
return parent::serialize();
}
public function __destruct() {
if ($this->needsCleanup) {
$this->nextIdDelete();
......
<?php
/**
* @file
* Contains \Drupal\system\Form\ModulesInstallConfirmForm.
*/
namespace Drupal\system\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Builds a confirmation form for required modules.
*
* Used internally in system_modules().
*/
class ModulesInstallConfirmForm extends ConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return t('Some required modules must be enabled');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return t('Continue');
}
/**
* {@inheritdoc}
*/
public function getCancelPath() {
return 'admin/modules';
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return t('Would you like to continue with the above?');
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'system_modules_confirm_form';
}
/**
* {@inheritdoc}
* @param array $modules
* The array of modules.
* @param array $storage
* Temporary storage of module dependency information.
*/
public function buildForm(array $form, array &$form_state, $modules = array(), $storage = array(), Request $request = NULL) {
$items = array();
$form['validation_modules'] = array('#type' => 'value', '#value' => $modules);
$form['status']['#tree'] = TRUE;
foreach ($storage['more_required'] as $info) {
$t_argument = array(
'@module' => $info['name'],
'@required' => implode(', ', $info['requires']),
);
$items[] = format_plural(count($info['requires']), 'You must enable the @required module to install @module.', 'You must enable the @required modules to install @module.', $t_argument);
}
foreach ($storage['missing_modules'] as $name => $info) {
$t_argument = array(
'@module' => $name,
'@depends' => implode(', ', $info['depends']),
);
$items[] = format_plural(count($info['depends']), 'The @module module is missing, so the following module will be disabled: @depends.', 'The @module module is missing, so the following modules will be disabled: @depends.', $t_argument);
}
$form['modules'] = array('#theme' => 'item_list', '#items' => $items);
return parent::buildForm($form, $form_state, $request);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
}
}
<?php
/**
* @file
* Contains \Drupal\system\Form\ModulesListConfirmForm.
*/
namespace Drupal\system\Form;
use Drupal\Core\Controller\ControllerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
/**
* Builds a confirmation form for enabling modules with dependencies.
*/
class ModulesListConfirmForm extends ConfirmFormBase implements ControllerInterface {
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The expirable key value store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
*/
protected $keyValueExpirable;
/**
* The translation manager service.
*
* @var \Drupal\Core\StringTranslation\TranslationManager
*/
protected $translationManager;
/**
* The request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* An associative list of modules to enable or disable.
*
* @var array
*/
protected $modules = array();
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('module_handler'),
$container->get('keyvalue.expirable')->get('module_list'),
$container->get('string_translation')
);
}
/**
* Constructs a ModulesListConfirmForm object.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
* The key value expirable factory.
* @param \Drupal\Core\StringTranslation\TranslationManager
* The translation manager.
*/
public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, TranslationManager $translation_manager) {
$this->moduleHandler = $module_handler;
$this->keyValueExpirable = $key_value_expirable;
$this->translationManager = $translation_manager;
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->translationManager->translate('Some required modules must be enabled');
}
/**
* {@inheritdoc}
*/
public function getCancelPath() {
return 'admin/modules';
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->translationManager->translate('Continue');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->translationManager->translate('Would you like to continue with the above?');
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'system_modules_confirm_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, Request $request = NULL) {
$account = $request->attributes->get('account')->id();
$this->modules = $this->keyValueExpirable->get($account);
// Redirect to the modules list page if the key value store is empty.
if (!$this->modules) {
return new RedirectResponse(url($this->getCancelPath(), array('absolute' => TRUE)));
}
// Store the request for use in the submit handler.
$this->request = $request;
$items = array();
// Display a list of required modules that have to be installed as well but
// were not manually selected.
foreach ($this->modules['dependencies'] as $module => $dependencies) {
$items[] = format_plural(count($dependencies), 'You must enable the @required module to install @module.', 'You must enable the @required modules to install @module.', array(
'@module' => $this->modules['enable'][$module],
'@required' => implode(', ', $dependencies),
));
}
foreach ($this->modules['missing'] as $name => $dependents) {
$items[] = format_plural(count($dependents), 'The @module module is missing, so the following module will be disabled: @depends.', 'The @module module is missing, so the following modules will be disabled: @depends.', array(
'@module' => $name,
'@depends' => implode(', ', $dependents),
));
}
$form['message'] = array(
'#theme' => 'item_list',
'#items' => $items,
);
return parent::buildForm($form, $form_state, $this->request);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
// Remove the key value store entry.
$account = $this->request->attributes->get('account')->id();
$this->keyValueExpirable->delete($account);
// Gets list of modules prior to install process.
$before = $this->moduleHandler->getModuleList();
// Installs, enables, and disables modules.
if (!empty($this->modules['enable'])) {
$this->moduleHandler->enable(array_keys($this->modules['enable']));
}
if (!empty($this->modules['disable'])) {
$this->moduleHandler->disable(array_keys($this->modules['disable']));
}
// Gets module list after install process, flushes caches and displays a
// message if there are changes.
if ($before != $this->moduleHandler->getModuleList()) {
drupal_flush_all_caches();
drupal_set_message($this->translationManager->translate('The configuration options have been saved.'));
}
$form_state['redirect'] = $this->getCancelPath();
}
}
<?php
/**
* @file
* Contains \Drupal\system\Form\ModulesListForm.
*/
namespace Drupal\system\Form;
use Drupal\Core\Controller\ControllerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactory;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Drupal\Component\Utility\Unicode;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Provides module enable/disable 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_parse_info_file() for info on module.info.yml
* descriptors.
*/
class ModulesListForm implements FormInterface, ControllerInterface {
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The expirable key value store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
*/
protected $keyValueExpirable;
/**
* The translation manager service.
*
* @var \Drupal\Core\StringTranslation\TranslationManager
*/
protected $translationManager;
/**
* The request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('module_handler'),
$container->get('keyvalue.expirable')->get('module_list'),
$container->get('string_translation')
);
}
/**
* Constructs a ModulesListForm object.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
* The key value expirable factory.
* @param \Drupal\Core\StringTranslation\TranslationManager
* The translation manager.
*/
public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, TranslationManager $translation_manager) {
$this->moduleHandler = $module_handler;
$this->keyValueExpirable = $key_value_expirable;
$this->translationManager = $translation_manager;
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'system_modules';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, Request $request = NULL) {
require_once DRUPAL_ROOT . '/core/includes/install.inc';
$distribution = check_plain(drupal_install_profile_distribution_name());
// Include system.admin.inc so we can use the sort callbacks.
$this->moduleHandler->loadInclude('system', 'inc', 'system.admin');
// Store the request for use in the submit handler.
$this->request = $request;
$form['filters'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array('table-filter', 'js-show'),
),
);
$form['filters']['text'] = array(
'#type' => 'search',
'#title' => $this->translationManager->translate('Search'),
'#size' => 30,
'#placeholder' => $this->translationManager->translate('Enter module name'),
'#attributes' => array(
'class' => array('table-filter-text'),
'data-table' => '#system-modules',
'autocomplete' => 'off',
'title' => $this->translationManager->translate('Enter a part of the module name or description to filter by.'),
),
);
// 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->translationManager->translate($package),
'#theme' => 'system_modules_details',
'#header' => array(
array('data' => '<span class="element-invisible">' . $this->translationManager->translate('Enabled') . '</span>', 'class' => array('checkbox')),
array('data' => $this->translationManager->translate('Name'), 'class' => array('name')),
array('data' => $this->translationManager->translate('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)),
),
// Ensure that the "Core" package comes first.
'#weight' => $package == 'Core' ? -10 : NULL,
);
}
// Lastly, sort all packages by title.
uasort($form['modules'], 'element_sort_by_title');
$form['#attached']['library'][] = array('system', 'drupal.system.modules');
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->translationManager->translate('Save configuration'),
);
return $form;
}
/**
* Builds a table row for the system modules page.
*
* @param array $modules
* The list existing modules.
* @param object $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, $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->translationManager->translate($module->info['description']);
$row['version']['#markup'] = $module->info['version'];
// Add links for each module.
// Used when checking if a module implements a help page.
$help = $this->moduleHandler->moduleExists('help') ? drupal_help_arg() : FALSE;
// Generate link for module's help page, if there is one.
$row['links']['help'] = array();
if ($help && $module->status && in_array($module->name, $this->moduleHandler->getImplementations('help'))) {
if ($this->moduleHandler->invoke($module->name, 'help', array("admin/help#$module->name", $help))) {
$row['links']['help'] = array(
'#type' => 'link',
'#title' => $this->translationManager->translate('Help'),
'#href' => "admin/help/$module->name",
'#options' => array('attributes' => array('class' => array('module-link', 'module-link-help'), 'title' => $this->translationManager->translate('Help'))),
);
}
}
// Generate link for module's permission, if the user has access to it.
$row['links']['permissions'] = array();
if ($module->status && user_access('administer permissions') && in_array($module->name, $this->moduleHandler->getImplementations('permission'))) {
$row['links']['permissions'] = array(
'#type' => 'link',
'#title' => $this->translationManager->translate('Permissions'),
'#href' => 'admin/people/permissions',
'#options' => array('fragment' => 'module-' . $module->name, 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => $this->translationManager->translate('Configure permissions'))),
);
}
// Generate link for module's configuration page, if it has one.
$row['links']['configure'] = array();
if ($module->status && isset($module->info['configure'])) {
if (($configure = menu_get_item($module->info['configure'])) && $configure['access']) {
$row['links']['configure'] = array(
'#type' => 'link',
'#title' => $this->translationManager->translate('Configure'),
'#href' => $configure['href'],
'#options' => array('attributes' => array('class' => array('module-link', 'module-link-configure'), 'title' => $configure['description'])),
);
}
}
// Present a checkbox for installing and indicating the status of a module.
$row['enable'] = array(
'#type' => 'checkbox',
'#title' => $this->translationManager->translate('Enable'),
'#default_value' => (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;
$status = '';
// Check the core compatibility.
if ($module->info['core'] != DRUPAL_CORE_COMPATIBILITY) {
$compatible = FALSE;
$status .= $this->translationManager->translate('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 ? '.*' : '');
$status .= $this->translationManager->translate('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) {
$row['enable']['#disabled'] = TRUE;
$row['description'] = array(
'#theme' => 'system_modules_incompatible',
'#message' => $status,
);
}
// 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->translationManager->translate('@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)) {