diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallConfirmForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallConfirmForm.php index 77c841c..0946132 100644 --- a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallConfirmForm.php +++ b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallConfirmForm.php @@ -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'), + $container->get('string_translation') + ); + } + + /** + * Constructs a ModulesUninstallConfirmForm object. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactory $key_value_expirable_factory + * The key value expirable factory. + * @param \Drupal\Core\StringTranslation\TranslationManager + * The translation manager. + */ + public function __construct(ModuleHandlerInterface $module_handler, KeyValueExpirableFactory $key_value_expirable_factory, TranslationManager $translation_manager) { + $this->moduleHandler = $module_handler; + $this->keyValueExpirable = $key_value_expirable_factory->get('modules_uninstall'); + $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,31 +121,45 @@ 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) { + // 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' => '

' . t('The following modules will be completely uninstalled from your site, and all data from these modules will be lost!') . '

'); - $form['modules'] = array('#theme' => 'item_list', '#items' => $uninstall); + // Store the request for use in the submit handler. + $this->request = $request; + + $data = system_rebuild_module_data(); + $form['text']['#markup'] = '

' . $this->translationManager->translate('The following modules will be completely uninstalled from your site, and all data from these modules will be lost!') . '

'; + $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); + return parent::buildForm($form, $form_state, $this->request); } /** * {@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(t('The selected modules have been uninstalled.')); + $form_state['redirect'] = 'admin/modules/uninstall'; } } diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php new file mode 100644 index 0000000..a779453 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php @@ -0,0 +1,174 @@ +get('module_handler'), + $container->get('keyvalue.expirable'), + $container->get('string_translation') + ); + } + + /** + * Constructs a ModulesUninstallForm object. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactory $key_value_expirable_factory + * The key value expirable factory. + * @param \Drupal\Core\StringTranslation\TranslationManager $translation_manager + * The translation manager. + */ + public function __construct(ModuleHandlerInterface $module_handler, KeyValueExpirableFactory $key_value_expirable_factory, TranslationManager $translation_manager) { + $this->moduleHandler = $module_handler; + $this->keyValueExpirable = $key_value_expirable_factory->get('modules_uninstall'); + $this->translationManager = $translation_manager; + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'system_modules_uninstall'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state, Request $request = NULL) { + $form['modules'] = array(); + + // Make sure the install API is available. + include_once DRUPAL_ROOT . '/core/includes/install.inc'; + + // Store the request for use in the submit handler. + $this->request = $request; + + // 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; + }); + + // 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'; + } +} diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 957db86..f9761ba 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -11,9 +11,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Drupal\Core\Datetime\DrupalDateTime; use Drupal\system\Form\ModulesInstallConfirmForm; -use Drupal\system\Form\ModulesUninstallConfirmForm; /** * Menu callback; Provide the administration overview page. @@ -764,113 +762,6 @@ function system_modules_submit($form, &$form_state) { } /** - * 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. */ function system_batch_page() { @@ -1233,11 +1124,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 = '
' . $disabled_message . '
'; } else { diff --git a/core/modules/system/system.module b/core/modules/system/system.module index a6a7786..7da7b4c 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -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. diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml index 1e09f79..ccc2917 100644 --- a/core/modules/system/system.routing.yml +++ b/core/modules/system/system.routing.yml @@ -158,6 +158,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: