Commit 04ef7cf8 authored by catch's avatar catch

Issue #1993202 by fubhy, h3rj4n, Pancho: Convert system_modules_uninstall() to a Controller.

parent 788cb06d
......@@ -8,27 +8,94 @@
namespace Drupal\system\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactory;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
/**
* Builds a confirmation form to uninstall selected modules.
*
* Used internally from system_modules_uninstall().
*/
class ModulesUninstallConfirmForm extends ConfirmFormBase {
class ModulesUninstallConfirmForm 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 array of modules to uninstall.
*
* @var array
*/
protected $modules = array();
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('module_handler'),
$container->get('keyvalue.expirable')->get('modules_uninstall'),
$container->get('string_translation')
);
}
/**
* Constructs a ModulesUninstallConfirmForm 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 t('Confirm uninstall');
return $this->translationManager->translate('Confirm uninstall');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return t('Uninstall');
return $this->translationManager->translate('Uninstall');
}
/**
......@@ -42,7 +109,7 @@ public function getCancelPath() {
* {@inheritdoc}
*/
public function getDescription() {
return t('Would you like to continue with uninstalling the above?');
return $this->translationManager->translate('Would you like to continue with uninstalling the above?');
}
/**
......@@ -54,23 +121,28 @@ public function getFormID() {
/**
* {@inheritdoc}
*
* @param array $modules
* The array of modules.
*/
public function buildForm(array $form, array &$form_state, $modules = array(), Request $request = NULL) {
$uninstall = array();
// Construct the hidden form elements and list items.
foreach ($modules as $module => $value) {
$info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info.yml');
$uninstall[] = $info['name'];
$form['uninstall'][$module] = array('#type' => 'hidden', '#value' => 1);
public function buildForm(array $form, array &$form_state, Request $request = NULL) {
// Store the request for use in the submit handler.
$this->request = $request;
// Retrieve the list of modules from the key value store.
$account = $request->attributes->get('account')->id();
$this->modules = $this->keyValueExpirable->get($account);
// Prevent this page from showing when the module list is empty.
if (empty($this->modules)) {
return new RedirectResponse('/admin/modules/uninstall');
}
$form['#confirmed'] = TRUE;
$form['uninstall']['#tree'] = TRUE;
$form['text'] = array('#markup' => '<p>' . t('The following modules will be completely uninstalled from your site, and <em>all data from these modules will be lost</em>!') . '</p>');
$form['modules'] = array('#theme' => 'item_list', '#items' => $uninstall);
$data = system_rebuild_module_data();
$form['text']['#markup'] = '<p>' . $this->translationManager->translate('The following modules will be completely uninstalled from your site, and <em>all data from these modules will be lost</em>!') . '</p>';
$form['modules'] = array(
'#theme' => 'item_list',
'#items' => array_map(function ($module) use ($data) {
return $data[$module]->info['name'];
}, $this->modules),
);
return parent::buildForm($form, $form_state, $request);
}
......@@ -79,6 +151,15 @@ public function buildForm(array $form, array &$form_state, $modules = array(), R
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
// Clear the key value store entry.
$account = $this->request->attributes->get('account')->id();
$this->keyValueExpirable->delete($account);
// Uninstall the modules.
$this->moduleHandler->uninstall($this->modules);
drupal_set_message($this->translationManager->translate('The selected modules have been uninstalled.'));
$form_state['redirect'] = 'admin/modules/uninstall';
}
}
<?php
/**
* @file
* Contains \Drupal\system\Form\ModulesUninstallForm.
*/
namespace Drupal\system\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactory;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Provides a form for uninstalling modules.
*/
class ModulesUninstallForm 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('modules_uninstall'),
$container->get('string_translation')
);
}
/**
* Constructs a ModulesUninstallForm 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 $translation_manager
* 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_uninstall';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, Request $request = NULL) {
// Store the request for use in the submit handler.
$this->request = $request;
// Make sure the install API is available.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
// Get a list of disabled, installed modules.
$modules = system_rebuild_module_data();
$disabled = array_filter($modules, function ($module) {
return empty($module->status) && drupal_get_installed_schema_version($module->name) > SCHEMA_UNINSTALLED;
});
$form['modules'] = array();
// Only build the rest of the form if there are any modules available to
// uninstall;
if (empty($disabled)) {
return $form;
}
$profile = drupal_get_profile();
// Sort all modules by their name.
$this->moduleHandler->loadInclude('system', 'inc', 'system.admin');
uasort($disabled, 'system_sort_modules_by_info_name');
$form['uninstall'] = array('#tree' => TRUE);
foreach ($disabled as $module) {
$name = $module->info['name'] ?: $module->name;
$form['modules'][$module->name]['#module_name'] = $name;
$form['modules'][$module->name]['name']['#markup'] = $name;
$form['modules'][$module->name]['description']['#markup'] = $this->translationManager->translate($module->info['description']);
$form['uninstall'][$module->name] = array(
'#type' => 'checkbox',
'#title' => $this->translationManager->translate('Uninstall @module module', array('@module' => $name)),
'#title_display' => 'invisible',
);
// All modules which depend on this one must be uninstalled first, before
// we can allow this module to be uninstalled. (The installation profile
// is excluded from this list.)
foreach (array_keys($module->required_by) as $dependent) {
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
$name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent;
$form['modules'][$module->name]['#dependents'][] = $name;
$form['uninstall'][$module->name]['#disabled'] = TRUE;
}
}
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->translationManager->translate('Uninstall'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
// Form submitted, but no modules selected.
if (!array_filter($form_state['values']['uninstall'])) {
drupal_set_message($this->translationManager->translate('No modules selected.'), 'error');
$form_state['redirect'] = 'admin/modules/uninstall';
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
// Save all the values in an expirable key value store.
$modules = $form_state['values']['uninstall'];
$uninstall = array_keys(array_filter($modules));
$account = $this->request->attributes->get('account')->id();
$this->keyValueExpirable->setWithExpire($account, $uninstall, 60);
// Redirect to the confirm form.
$form_state['redirect'] = 'admin/modules/uninstall/confirm';
}
}
......@@ -7,10 +7,10 @@
use Drupal\system\DateFormatInterface;
use Drupal\system\Form\ModulesInstallConfirmForm;
use Drupal\system\Form\ModulesUninstallConfirmForm;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Drupal\Core\Datetime\DrupalDateTime;
/**
* Menu callback; Provide the administration overview page.
......@@ -763,113 +763,6 @@ function system_modules_submit($form, &$form_state) {
$form_state['redirect'] = 'admin/modules';
}
/**
* Uninstall functions
*/
/**
* Form constructor for the uninstalling disabled modules form.
*
* @see system_menu()
* @see system_modules_uninstall_validate()
* @see system_modules_uninstall_submit()
*
* @ingroup forms
*/
function system_modules_uninstall($form, $form_state = NULL) {
// Make sure the install API is available.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
// Display the confirm form if any modules have been submitted.
if (!empty($form_state['storage']['uninstall']) && $modules = array_filter($form_state['storage']['uninstall'])) {
// Contents of confirm form is injected here because already in form
// building function.
$confirm_form = new ModulesUninstallConfirmForm();
return $confirm_form->buildForm($form, $form_state, $modules, Drupal::request());
}
// Get a list of disabled, installed modules.
$all_modules = system_rebuild_module_data();
$disabled_modules = array();
foreach ($all_modules as $name => $module) {
if (empty($module->status) && drupal_get_installed_schema_version($name) > SCHEMA_UNINSTALLED) {
$disabled_modules[$name] = $module;
}
}
// Only build the rest of the form if there are any modules available to
// uninstall.
if (!empty($disabled_modules)) {
$profile = drupal_get_profile();
uasort($disabled_modules, 'system_sort_modules_by_info_name');
$form['uninstall'] = array('#tree' => TRUE);
foreach ($disabled_modules as $module) {
$module_name = $module->info['name'] ? $module->info['name'] : $module->name;
$form['modules'][$module->name]['#module_name'] = $module_name;
$form['modules'][$module->name]['name']['#markup'] = $module_name;
$form['modules'][$module->name]['description']['#markup'] = t($module->info['description']);
$form['uninstall'][$module->name] = array(
'#type' => 'checkbox',
'#title' => t('Uninstall @module module', array('@module' => $module_name)),
'#title_display' => 'invisible',
);
// All modules which depend on this one must be uninstalled first, before
// we can allow this module to be uninstalled. (The installation profile
// is excluded from this list.)
foreach (array_keys($module->required_by) as $dependent) {
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
$dependent_name = isset($all_modules[$dependent]->info['name']) ? $all_modules[$dependent]->info['name'] : $dependent;
$form['modules'][$module->name]['#required_by'][] = $dependent_name;
$form['uninstall'][$module->name]['#disabled'] = TRUE;
}
}
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Uninstall'),
);
$form['#action'] = url('admin/modules/uninstall/confirm');
}
else {
$form['modules'] = array();
}
return $form;
}
/**
* Validates the submitted uninstall form.
*/
function system_modules_uninstall_validate($form, &$form_state) {
// Form submitted, but no modules selected.
if (!count(array_filter($form_state['values']['uninstall']))) {
drupal_set_message(t('No modules selected.'), 'error');
return new RedirectResponse(url('admin/modules/uninstall', array('absolute' => TRUE)));
}
}
/**
* Processes the submitted uninstall form.
*/
function system_modules_uninstall_submit($form, &$form_state) {
// Make sure the install API is available.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
if (!empty($form['#confirmed'])) {
// Call the uninstall routine for each selected module.
$modules = array_keys($form_state['values']['uninstall']);
module_uninstall($modules);
drupal_set_message(t('The selected modules have been uninstalled.'));
$form_state['redirect'] = 'admin/modules/uninstall';
}
else {
$form_state['storage'] = $form_state['values'];
$form_state['rebuild'] = TRUE;
}
}
/**
* Default page callback for batches.
*/
......@@ -1240,11 +1133,11 @@ function theme_system_modules_uninstall($variables) {
// Display table.
$rows = array();
foreach (element_children($form['modules']) as $module) {
if (!empty($form['modules'][$module]['#required_by'])) {
$disabled_message = format_plural(count($form['modules'][$module]['#required_by']),
if (!empty($form['modules'][$module]['#dependents'])) {
$disabled_message = format_plural(count($form['modules'][$module]['#dependents']),
'To uninstall @module, the following module must be uninstalled first: @required_modules',
'To uninstall @module, the following modules must be uninstalled first: @required_modules',
array('@module' => $form['modules'][$module]['#module_name'], '@required_modules' => implode(', ', $form['modules'][$module]['#required_by'])));
array('@module' => $form['modules'][$module]['#module_name'], '@required_modules' => implode(', ', $form['modules'][$module]['#dependents'])));
$disabled_message = '<div class="admin-requirements">' . $disabled_message . '</div>';
}
else {
......
......@@ -736,17 +736,14 @@ function system_menu() {
);
$items['admin/modules/uninstall'] = array(
'title' => 'Uninstall',
'page arguments' => array('system_modules_uninstall'),
'access arguments' => array('administer modules'),
'route_name' => 'system_modules_uninstall',
'type' => MENU_LOCAL_TASK,
'file' => 'system.admin.inc',
'weight' => 20,
);
$items['admin/modules/uninstall/confirm'] = array(
'title' => 'Uninstall',
'access arguments' => array('administer modules'),
'route_name' => 'system_modules_uninstall_confirm',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
'file' => 'system.admin.inc',
);
// Configuration.
......
......@@ -165,6 +165,20 @@ system_theme_settings_global:
requirements:
_permission: 'administer themes'
system_modules_uninstall:
pattern: 'admin/modules/uninstall'
defaults:
_form: 'Drupal\system\Form\ModulesUninstallForm'
requirements:
_permission: 'administer modules'
system_modules_uninstall_confirm:
pattern: 'admin/modules/uninstall/confirm'
defaults:
_form: 'Drupal\system\Form\ModulesUninstallConfirmForm'
requirements:
_permission: 'administer modules'
system_timezone:
pattern: '/system/timezone'
defaults:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment