Issue #1199946 by alexpott, fubhy, bojanz, steinmb, chx, catch: Fixed Disabled modules are broken beyond repair so the 'disable' functionality needs to be removed.

8.0.x
Dries 2013-09-19 18:22:53 +02:00
parent 6b7bdcdd8c
commit 65b155d9c2
97 changed files with 855 additions and 1512 deletions

View File

@ -86,8 +86,10 @@ function entity_invoke_bundle_hook($hook, $entity_type, $bundle, $bundle_new = N
// Notify the entity storage controller. // Notify the entity storage controller.
$method = 'onBundle' . ucfirst($hook); $method = 'onBundle' . ucfirst($hook);
\Drupal::entityManager()->getStorageController($entity_type)->$method($bundle, $bundle_new); $storage_controller = \Drupal::entityManager()->getStorageController($entity_type);
if (method_exists($storage_controller, $method)) {
$storage_controller->$method($bundle, $bundle_new);
}
// Invoke hook_entity_bundle_*() hooks. // Invoke hook_entity_bundle_*() hooks.
\Drupal::moduleHandler()->invokeAll('entity_bundle_' . $hook, array($entity_type, $bundle, $bundle_new)); \Drupal::moduleHandler()->invokeAll('entity_bundle_' . $hook, array($entity_type, $bundle, $bundle_new));
} }

View File

@ -995,7 +995,7 @@ function install_base_system(&$install_state) {
// Enable the user module so that sessions can be recorded during the // Enable the user module so that sessions can be recorded during the
// upcoming bootstrap step. // upcoming bootstrap step.
module_enable(array('user'), FALSE); Drupal::moduleHandler()->install(array('user'), FALSE);
// Save the list of other modules to install for the upcoming tasks. // Save the list of other modules to install for the upcoming tasks.
// variable_set() can be used now that system.module is installed. // variable_set() can be used now that system.module is installed.
@ -2037,7 +2037,7 @@ function _install_module_batch($module, $module_name, &$context) {
// loaded by drupal_bootstrap in subsequent batch requests, and other // loaded by drupal_bootstrap in subsequent batch requests, and other
// modules possibly depending on it can safely perform their installation // modules possibly depending on it can safely perform their installation
// steps. // steps.
module_enable(array($module), FALSE); Drupal::moduleHandler()->install(array($module), FALSE);
$context['results'][] = $module; $context['results'][] = $module;
$context['message'] = t('Installed %module module.', array('%module' => $module_name)); $context['message'] = t('Installed %module module.', array('%module' => $module_name));
} }
@ -2529,7 +2529,7 @@ function install_configure_form_submit($form, &$form_state) {
// Enable update.module if this option was selected. // Enable update.module if this option was selected.
if ($form_state['values']['update_status_module'][1]) { if ($form_state['values']['update_status_module'][1]) {
module_enable(array('file', 'update'), FALSE); Drupal::moduleHandler()->install(array('file', 'update'), FALSE);
// Add the site maintenance account's email address to the list of // Add the site maintenance account's email address to the list of
// addresses to be notified when updates are available, if selected. // addresses to be notified when updates are available, if selected.

View File

@ -203,8 +203,9 @@ function language_types_disable($types) {
*/ */
function language_types_set(array $configurable_language_types) { function language_types_set(array $configurable_language_types) {
// Ensure that we are getting the defined language negotiation information. An // Ensure that we are getting the defined language negotiation information. An
// invocation of module_enable() or module_disable() could outdate the cached // invocation of \Drupal\Core\Extension\ModuleHandler::install() or
// information. // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the
// cached information.
drupal_static_reset('language_types_info'); drupal_static_reset('language_types_info');
drupal_static_reset('language_negotiation_info'); drupal_static_reset('language_negotiation_info');
@ -343,8 +344,9 @@ function language_negotiation_get_switch_links($type, $path) {
*/ */
function language_negotiation_purge() { function language_negotiation_purge() {
// Ensure that we are getting the defined language negotiation information. An // Ensure that we are getting the defined language negotiation information. An
// invocation of module_enable() or module_disable() could outdate the cached // invocation of \Drupal\Core\Extension\ModuleHandler::install() or
// information. // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the
// cached information.
drupal_static_reset('language_negotiation_info'); drupal_static_reset('language_negotiation_info');
drupal_static_reset('language_types_info'); drupal_static_reset('language_types_info');

View File

@ -201,32 +201,21 @@ function module_load_include($type, $module, $name = NULL) {
return FALSE; return FALSE;
} }
/** /**
* Enables or installs a given list of modules. * Installs a given list of modules.
* *
* @deprecated as of Drupal 8.0. Use * @deprecated as of Drupal 8.0. Use
* \Drupal::moduleHandler()->enable($module_list, $enable_dependencies = TRUE). * \Drupal::moduleHandler()->install($module_list, $enable_dependencies = TRUE)
*/ */
function module_enable($module_list, $enable_dependencies = TRUE) { function module_install($module_list, $enable_dependencies = TRUE) {
return \Drupal::moduleHandler()->enable($module_list, $enable_dependencies); return \Drupal::moduleHandler()->install($module_list, $enable_dependencies);
} }
/** /**
* Disables a given set of modules. * Installs a given list of modules.
* *
* @deprecated as of Drupal 8.0. Use * @deprecated as of Drupal 8.0. Use
* \Drupal::moduleHandler()->disable($module_list, $disable_dependents = TRUE). * \Drupal::moduleHandler()->install($module_list, $enable_dependencies = TRUE).
*/
function module_disable($module_list, $disable_dependents = TRUE) {
\Drupal::moduleHandler()->disable($module_list, $disable_dependents);
}
/**
* Uninstalls a given list of disabled modules.
*
* @deprecated as of Drupal 8.0. Use
* \Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents = TRUE).
*/ */
function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) { function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) {
return \Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents); return \Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents);
@ -332,7 +321,7 @@ function module_set_weight($module, $weight) {
->save(); ->save();
// Prepare the new module list, sorted by weight, including filenames. // Prepare the new module list, sorted by weight, including filenames.
// @see module_enable() // @see Drupal\Core\Extension\ModuleHandler::install()
$module_handler = \Drupal::moduleHandler(); $module_handler = \Drupal::moduleHandler();
$current_module_filenames = $module_handler->getModuleList(); $current_module_filenames = $module_handler->getModuleList();
$current_modules = array_fill_keys(array_keys($current_module_filenames), 0); $current_modules = array_fill_keys(array_keys($current_module_filenames), 0);
@ -345,13 +334,6 @@ function module_set_weight($module, $weight) {
$module_handler->setModuleList($module_filenames); $module_handler->setModuleList($module_filenames);
return; return;
} }
$disabled_config = \Drupal::config('system.module.disabled');
if ($disabled_config->get($module) !== NULL) {
$disabled_config
->set($module, $weight)
->save();
return;
}
} }
/** /**

View File

@ -335,7 +335,6 @@ function update_prepare_d8_bootstrap() {
} }
$module_config = \Drupal::config('system.module'); $module_config = \Drupal::config('system.module');
$disabled_modules = \Drupal::config('system.module.disabled');
$theme_config = \Drupal::config('system.theme'); $theme_config = \Drupal::config('system.theme');
$disabled_themes = \Drupal::config('system.theme.disabled'); $disabled_themes = \Drupal::config('system.theme.disabled');
$schema_store = \Drupal::keyValue('system.schema'); $schema_store = \Drupal::keyValue('system.schema');
@ -378,9 +377,6 @@ function update_prepare_d8_bootstrap() {
if ($record->status && isset($module_data[$record->name])) { if ($record->status && isset($module_data[$record->name])) {
$module_config->set('enabled.' . $record->name, $record->weight); $module_config->set('enabled.' . $record->name, $record->weight);
} }
else {
$disabled_modules->set($record->name, $record->weight);
}
} }
elseif ($record->type == 'theme') { elseif ($record->type == 'theme') {
if ($record->status) { if ($record->status) {
@ -399,7 +395,6 @@ function update_prepare_d8_bootstrap() {
$sorted_with_filenames[$m] = drupal_get_filename('module', $m); $sorted_with_filenames[$m] = drupal_get_filename('module', $m);
} }
\Drupal::moduleHandler()->setModuleList($sorted_with_filenames); \Drupal::moduleHandler()->setModuleList($sorted_with_filenames);
$disabled_modules->save();
$theme_config->save(); $theme_config->save();
$disabled_themes->save(); $disabled_themes->save();
@ -490,8 +485,7 @@ function update_prepare_stored_includes() {
*/ */
function update_prepare_d8_language() { function update_prepare_d8_language() {
if (db_table_exists('languages')) { if (db_table_exists('languages')) {
Drupal::moduleHandler()->install(array('language'));
module_enable(array('language'));
$languages = db_select('languages', 'l') $languages = db_select('languages', 'l')
->fields('l') ->fields('l')
@ -683,7 +677,7 @@ function update_fix_d8_requirements() {
// Make sure that file.module is enabled as it is required for the user // Make sure that file.module is enabled as it is required for the user
// picture upgrade path. // picture upgrade path.
module_enable(array('file')); Drupal::moduleHandler()->install(array('file'));
$schema = array( $schema = array(
'description' => 'Generic key/value storage table with an expiration.', 'description' => 'Generic key/value storage table with an expiration.',
@ -727,8 +721,8 @@ function update_fix_d8_requirements() {
// views configurations. // views configurations.
// Like any other module APIs and services, Views' services are not available // Like any other module APIs and services, Views' services are not available
// in update.php. Existing listings are migrated into configuration, using // in update.php. Existing listings are migrated into configuration, using
// the limited standard tools of raw database queries and \Drupal::config(). // the limited standard tools of raw database queries and Drupal::config().
module_enable(array('views')); \Drupal::moduleHandler()->install(array('views'));
update_variable_set('update_d8_requirements', TRUE); update_variable_set('update_d8_requirements', TRUE);
} }

View File

@ -11,11 +11,10 @@ use Drupal\Component\Graph\Graph;
use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Parser;
use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
* Class that manages enabled modules in a Drupal installation. * Class that manages modules in a Drupal installation.
*/ */
class ModuleHandler implements ModuleHandlerInterface { class ModuleHandler implements ModuleHandlerInterface {
@ -29,7 +28,7 @@ class ModuleHandler implements ModuleHandlerInterface {
protected $loadedFiles; protected $loadedFiles;
/** /**
* List of enabled modules. * List of installed modules.
* *
* @var array * @var array
* An associative array whose keys are the names of the modules and whose * An associative array whose keys are the names of the modules and whose
@ -69,7 +68,7 @@ class ModuleHandler implements ModuleHandlerInterface {
* Constructs a ModuleHandler object. * Constructs a ModuleHandler object.
* *
* @param array $module_list * @param array $module_list
* An associative array whose keys are the names of enabled modules and * An associative array whose keys are the names of installed modules and
* whose values are the module filenames. This is normally the * whose values are the module filenames. This is normally the
* %container.modules% parameter being set up by DrupalKernel. * %container.modules% parameter being set up by DrupalKernel.
* *
@ -502,45 +501,60 @@ class ModuleHandler implements ModuleHandlerInterface {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function enable($module_list, $enable_dependencies = TRUE) { public function install(array $module_list, $enable_dependencies = TRUE) {
$module_config = \Drupal::config('system.module');
if ($enable_dependencies) { if ($enable_dependencies) {
// Get all module data so we can find dependencies and sort. // Get all module data so we can find dependencies and sort.
$module_data = system_rebuild_module_data(); $module_data = system_rebuild_module_data();
// Create an associative array with weights as values. $module_list = $module_list ? array_combine($module_list, $module_list) : array();
$module_list = array_flip(array_values($module_list)); if (array_diff_key($module_list, $module_data)) {
// One or more of the given modules doesn't exist.
while (list($module) = each($module_list)) {
if (!isset($module_data[$module])) {
// This module is not found in the filesystem, abort.
return FALSE; return FALSE;
} }
if ($module_data[$module]->status) {
// Skip already enabled modules.
unset($module_list[$module]);
continue;
}
$module_list[$module] = $module_data[$module]->sort;
// Add dependencies to the list, with a placeholder weight. // Only process currently uninstalled modules.
// The new modules will be processed as the while loop continues. $installed_modules = $module_config->get('enabled') ?: array();
foreach (array_keys($module_data[$module]->requires) as $dependency) { if (!$module_list = array_diff_key($module_list, $installed_modules)) {
if (!isset($module_list[$dependency])) { // Nothing to do. All modules already installed.
$module_list[$dependency] = 0;
}
}
}
if (!$module_list) {
// Nothing to do. All modules already enabled.
return TRUE; return TRUE;
} }
// Sort the module list by pre-calculated weights. // Conditionally add the dependencies to the list of modules.
if ($enable_dependencies) {
// Add dependencies to the list. The new modules will be processed as the
// while loop continues.
while (list($module) = each($module_list)) {
foreach (array_keys($module_data[$module]->requires) as $dependency) {
if (!isset($module_data[$dependency])) {
// The dependency does not exist.
return FALSE;
}
// Skip already installed modules.
if (!isset($module_list[$dependency]) && !isset($installed_modules[$dependency])) {
$module_list[$dependency] = $dependency;
}
}
}
}
// Set the actual module weights.
$module_list = array_map(function ($module) use ($module_data) {
return $module_data[$module]->sort;
}, $module_list);
// Sort the module list by their weights (reverse).
arsort($module_list); arsort($module_list);
$module_list = array_keys($module_list); $module_list = array_keys($module_list);
} }
// Required for module installation checks.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
$modules_installed = array();
foreach ($module_list as $module) { foreach ($module_list as $module) {
$enabled = $module_config->get("enabled.$module") !== NULL;
if (!$enabled) {
// Throw an exception if the module name is too long. // Throw an exception if the module name is too long.
if (strlen($module) > DRUPAL_EXTENSION_NAME_MAX_LENGTH) { if (strlen($module) > DRUPAL_EXTENSION_NAME_MAX_LENGTH) {
throw new ExtensionNameLengthException(format_string('Module name %name is over the maximum allowed length of @max characters.', array( throw new ExtensionNameLengthException(format_string('Module name %name is over the maximum allowed length of @max characters.', array(
@ -548,33 +562,11 @@ class ModuleHandler implements ModuleHandlerInterface {
'@max' => DRUPAL_EXTENSION_NAME_MAX_LENGTH, '@max' => DRUPAL_EXTENSION_NAME_MAX_LENGTH,
))); )));
} }
}
// Required for module installation checks.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
$modules_installed = array();
$modules_enabled = array();
$module_config = \Drupal::config('system.module');
$disabled_config = \Drupal::config('system.module.disabled');
foreach ($module_list as $module) {
// Only process modules that are not already enabled.
// A module is only enabled if it is configured as enabled. Custom or
// overridden module handlers might contain the module already, which means
// that it might be loaded, but not necessarily installed or enabled.
$enabled = $module_config->get("enabled.$module") !== NULL;
if (!$enabled) {
$weight = $disabled_config->get($module);
if ($weight === NULL) {
$weight = 0;
}
$module_config $module_config
->set("enabled.$module", $weight) ->set("enabled.$module", 0)
->set('enabled', module_config_sort($module_config->get('enabled'))) ->set('enabled', module_config_sort($module_config->get('enabled')))
->save(); ->save();
$disabled_config
->clear($module)
->save();
// Prepare the new module list, sorted by weight, including filenames. // Prepare the new module list, sorted by weight, including filenames.
// This list is used for both the ModuleHandler and DrupalKernel. It needs // This list is used for both the ModuleHandler and DrupalKernel. It needs
@ -591,12 +583,11 @@ class ModuleHandler implements ModuleHandlerInterface {
$module_filenames = array(); $module_filenames = array();
foreach ($current_modules as $name => $weight) { foreach ($current_modules as $name => $weight) {
if (isset($current_module_filenames[$name])) { if (isset($current_module_filenames[$name])) {
$filename = $current_module_filenames[$name]; $module_filenames[$name] = $current_module_filenames[$name];
} }
else { else {
$filename = drupal_get_filename('module', $name); $module_filenames[$name] = drupal_get_filename('module', $name);
} }
$module_filenames[$name] = $filename;
} }
// Update the module handler in order to load the module's code. // Update the module handler in order to load the module's code.
@ -618,7 +609,7 @@ class ModuleHandler implements ModuleHandlerInterface {
// taken over as %container.modules% parameter, which is passed to a fresh // taken over as %container.modules% parameter, which is passed to a fresh
// ModuleHandler instance upon first retrieval. // ModuleHandler instance upon first retrieval.
// @todo install_begin_request() creates a container without a kernel. // @todo install_begin_request() creates a container without a kernel.
if ($kernel = drupal_container()->get('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) { if ($kernel = \Drupal::service('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
$kernel->updateModules($module_filenames, $module_filenames); $kernel->updateModules($module_filenames, $module_filenames);
} }
@ -628,13 +619,12 @@ class ModuleHandler implements ModuleHandlerInterface {
drupal_theme_rebuild(); drupal_theme_rebuild();
// Allow modules to react prior to the installation of a module. // Allow modules to react prior to the installation of a module.
$this->invokeAll('modules_preinstall', array(array($module))); $this->invokeAll('module_preinstall', array($module));
// Clear the entity info cache before importing new configuration. // Clear the entity info cache before importing new configuration.
entity_info_cache_clear(); entity_info_cache_clear();
// Now install the module if necessary. // Now install the module's schema if necessary.
if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) {
drupal_install_schema($module); drupal_install_schema($module);
// Set the schema version to the number of the last update provided // Set the schema version to the number of the last update provided
@ -652,24 +642,15 @@ class ModuleHandler implements ModuleHandlerInterface {
$version = max($version, $last_removed); $version = max($version, $last_removed);
} }
drupal_set_installed_schema_version($module, $version); drupal_set_installed_schema_version($module, $version);
// Record the fact that it was installed.
$modules_installed[] = $module;
// Allow the module to perform install tasks. // Allow the module to perform install tasks.
$this->invoke($module, 'install'); $this->invoke($module, 'install');
// Record the fact that it was installed. // Record the fact that it was installed.
$modules_installed[] = $module;
watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO); watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
} }
// Allow modules to react prior to the enabling of a module.
entity_info_cache_clear();
$this->invokeAll('modules_preenable', array(array($module)));
// Enable the module.
$this->invoke($module, 'enable');
// Record the fact that it was enabled.
$modules_enabled[] = $module;
watchdog('system', '%module module enabled.', array('%module' => $module), WATCHDOG_INFO);
}
} }
// If any modules were newly installed, invoke hook_modules_installed(). // If any modules were newly installed, invoke hook_modules_installed().
@ -677,142 +658,66 @@ class ModuleHandler implements ModuleHandlerInterface {
$this->invokeAll('modules_installed', array($modules_installed)); $this->invokeAll('modules_installed', array($modules_installed));
} }
// If any modules were newly enabled, invoke hook_modules_enabled().
if (!empty($modules_enabled)) {
$this->invokeAll('modules_enabled', array($modules_enabled));
}
return TRUE; return TRUE;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
function disable($module_list, $disable_dependents = TRUE) { public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
if ($disable_dependents) { // Get all module data so we can find dependencies and sort.
// Get all module data so we can find dependents and sort.
$module_data = system_rebuild_module_data(); $module_data = system_rebuild_module_data();
// Create an associative array with weights as values. $module_list = $module_list ? array_combine($module_list, $module_list) : array();
$module_list = array_flip(array_values($module_list)); if (array_diff_key($module_list, $module_data)) {
// One or more of the given modules doesn't exist.
$profile = drupal_get_profile();
while (list($module) = each($module_list)) {
if (!isset($module_data[$module]) || !$module_data[$module]->status) {
// This module doesn't exist or is already disabled, skip it.
unset($module_list[$module]);
continue;
}
$module_list[$module] = $module_data[$module]->sort;
// Add dependent modules to the list, with a placeholder weight.
// The new modules will be processed as the while loop continues.
foreach ($module_data[$module]->required_by as $dependent => $dependent_data) {
if (!isset($module_list[$dependent]) && $dependent != $profile) {
$module_list[$dependent] = 0;
}
}
}
// Sort the module list by pre-calculated weights.
asort($module_list);
$module_list = array_keys($module_list);
}
$invoke_modules = array();
$module_config = \Drupal::config('system.module');
$disabled_config = \Drupal::config('system.module.disabled');
foreach ($module_list as $module) {
// Only process modules that are enabled.
// A module is only enabled if it is configured as enabled. Custom or
// overridden module handlers might contain the module already, which means
// that it might be loaded, but not necessarily installed or enabled.
$enabled = $module_config->get("enabled.$module") !== NULL;
if ($enabled) {
module_load_install($module);
module_invoke($module, 'disable');
$disabled_config
->set($module, $module_config->get($module))
->save();
$module_config
->clear("enabled.$module")
->save();
// Update the module handler to remove the module.
// The current ModuleHandler instance is obsolete with the kernel rebuild
// below.
$module_filenames = $this->getModuleList();
unset($module_filenames[$module]);
$this->setModuleList($module_filenames);
// Record the fact that it was disabled.
$invoke_modules[] = $module;
watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO);
}
}
if (!empty($invoke_modules)) {
// @todo Most of the following should happen in above loop already.
// Refresh the system list to exclude the disabled modules.
// @todo Only needed to rebuild theme info.
// @see system_list_reset()
system_list_reset();
entity_info_cache_clear();
// Invoke hook_modules_disabled before disabling modules,
// so we can still call module hooks to get information.
$this->invokeAll('modules_disabled', array($invoke_modules));
// Update the kernel to exclude the disabled modules.
$enabled = $this->getModuleList();
drupal_container()->get('kernel')->updateModules($enabled, $enabled);
// Update the theme registry to remove the newly-disabled module.
drupal_theme_rebuild();
}
}
/**
* {@inheritdoc}
*/
public function uninstall($module_list = array(), $uninstall_dependents = TRUE) {
if ($uninstall_dependents) {
// Get all module data so we can find dependents and sort.
$module_data = system_rebuild_module_data();
// Create an associative array with weights as values.
$module_list = array_flip(array_values($module_list));
$profile = drupal_get_profile();
while (list($module) = each($module_list)) {
if (!isset($module_data[$module]) || drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED) {
// This module doesn't exist or is already uninstalled. Skip it.
unset($module_list[$module]);
continue;
}
$module_list[$module] = $module_data[$module]->sort;
// If the module has any dependents which are not already uninstalled and
// not included in the passed-in list, abort. It is not safe to uninstall
// them automatically because uninstalling a module is a destructive
// operation.
foreach (array_keys($module_data[$module]->required_by) as $dependent) {
if (!isset($module_list[$dependent]) && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED && $dependent != $profile) {
return FALSE; return FALSE;
} }
// Only process currently installed modules.
$module_config = \Drupal::config('system.module');
$installed_modules = $module_config->get('enabled') ?: array();
if (!$module_list = array_intersect_key($module_list, $installed_modules)) {
// Nothing to do. All modules already uninstalled.
return TRUE;
}
if ($uninstall_dependents) {
// Add dependent modules to the list. The new modules will be processed as
// the while loop continues.
$profile = drupal_get_profile();
while (list($module) = each($module_list)) {
foreach (array_keys($module_data[$module]->required_by) as $dependent) {
if (!isset($module_data[$dependent])) {
// The dependent module does not exist.
return FALSE;
}
// Skip already uninstalled modules.
if (isset($installed_modules[$dependent]) && !isset($module_list[$dependent]) && $dependent != $profile) {
$module_list[$dependent] = TRUE;
}
}
} }
} }
// Sort the module list by pre-calculated weights. // Set the actual module weights.
$module_list = array_map(function ($module) use ($module_data) {
return $module_data[$module]->sort;
}, $module_list);
// Sort the module list by their weights.
asort($module_list); asort($module_list);
$module_list = array_keys($module_list); $module_list = array_keys($module_list);
}
// Only process modules that are enabled. A module is only enabled if it is
// configured as enabled. Custom or overridden module handlers might contain
// the module already, which means that it might be loaded, but not
// necessarily installed.
$schema_store = \Drupal::keyValue('system.schema'); $schema_store = \Drupal::keyValue('system.schema');
$disabled_config = \Drupal::config('system.module.disabled');
foreach ($module_list as $module) { foreach ($module_list as $module) {
// Allow modules to react prior to the uninstallation of a module.
$this->invokeAll('module_preuninstall', array($module));
// Uninstall the module. // Uninstall the module.
module_load_install($module); module_load_install($module);
$this->invoke($module, 'uninstall'); $this->invoke($module, 'uninstall');
@ -821,7 +726,55 @@ class ModuleHandler implements ModuleHandlerInterface {
// Remove all configuration belonging to the module. // Remove all configuration belonging to the module.
config_uninstall_default_config('module', $module); config_uninstall_default_config('module', $module);
// Remove any cache bins defined by the module. // Remove the module's entry from the config.
$module_config->clear("enabled.$module")->save();
// Update the module handler to remove the module.
// The current ModuleHandler instance is obsolete with the kernel rebuild
// below.
$module_filenames = $this->getModuleList();
unset($module_filenames[$module]);
$this->setModuleList($module_filenames);
// Remove any potential cache bins provided by the module.
$this->removeCacheBins($module);
// Refresh the system list to exclude the uninstalled modules.
// @todo Only needed to rebuild theme info.
// @see system_list_reset()
system_list_reset();
// Clear the entity info cache.
entity_info_cache_clear();
// Update the kernel to exclude the uninstalled modules.
\Drupal::service('kernel')->updateModules($module_filenames, $module_filenames);
// Update the theme registry to remove the newly uninstalled module.
drupal_theme_rebuild();
watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
$schema_store->delete($module);
}
drupal_get_installed_schema_version(NULL, TRUE);
// Let other modules react.
$this->invokeAll('modules_uninstalled', array($module_list));
drupal_flush_all_caches();
return TRUE;
}
/**
* Helper method for removing all cache bins registered by a given module.
*
* @param string $module
* The name of the module for which to remove all registered cache bins.
*/
protected function removeCacheBins($module) {
// Remove any cache bins defined by a module.
$service_yaml_file = drupal_get_path('module', $module) . "/$module.services.yml"; $service_yaml_file = drupal_get_path('module', $module) . "/$module.services.yml";
if (file_exists($service_yaml_file)) { if (file_exists($service_yaml_file)) {
$parser = new Parser; $parser = new Parser;
@ -852,20 +805,6 @@ class ModuleHandler implements ModuleHandlerInterface {
} }
} }
} }
watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
$schema_store->delete($module);
$disabled_config->clear($module);
}
$disabled_config->save();
drupal_get_installed_schema_version(NULL, TRUE);
if (!empty($module_list)) {
// Let other modules react.
$this->invokeAll('modules_uninstalled', array($module_list));
}
return TRUE;
} }
/** /**

View File

@ -253,77 +253,50 @@ interface ModuleHandlerInterface {
public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL); public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL);
/** /**
* Enables or installs a given list of modules. * Installs a given list of modules.
*
* Definitions:
* - "Enabling" is the process of activating a module for use by Drupal.
* - "Disabling" is the process of deactivating a module.
* - "Installing" is the process of enabling it for the first time or after it
* has been uninstalled.
* - "Uninstalling" is the process of removing all traces of a module.
* *
* Order of events: * Order of events:
* - Gather and add module dependencies to $module_list (if applicable). * - Gather and add module dependencies to $module_list (if applicable).
* - For each module that is being enabled: * - For each module that is being installed:
* - Invoke hook_module_preinstall().
* - Install module schema and update system registries and caches. * - Install module schema and update system registries and caches.
* - If the module is being enabled for the first time or had been * - Invoke hook_install() and add it to the list of installed modules.
* uninstalled, invoke hook_install() and add it to the list of installed
* modules.
* - Invoke hook_enable().
* - Invoke hook_modules_installed(). * - Invoke hook_modules_installed().
* - Invoke hook_modules_enabled().
* *
* @param $module_list * @param array $module_list
* An array of module names. * An array of module names.
* @param $enable_dependencies * @param bool $enable_dependencies
* If TRUE, dependencies will automatically be added and enabled in the * (optional) If TRUE, dependencies will automatically be installed in the
* correct order. This incurs a significant performance cost, so use FALSE * correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order. * if you know $module_list is already complete.
* *
* @return * @return bool
* FALSE if one or more dependencies are missing, TRUE otherwise. * FALSE if one or more dependencies are missing, TRUE otherwise.
* *
* @see hook_module_preinstall()
* @see hook_install() * @see hook_install()
* @see hook_enable()
* @see hook_modules_installed() * @see hook_modules_installed()
* @see hook_modules_enabled()
*/ */
public function enable($module_list, $enable_dependencies = TRUE); public function install(array $module_list, $enable_dependencies = TRUE);
/**
* Disables a given set of modules.
*
* @param $module_list
* An array of module names.
* @param $disable_dependents
* If TRUE, dependent modules will automatically be added and disabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
*/
public function disable($module_list, $disable_dependents = TRUE);
/** /**
* Uninstalls a given list of disabled modules. * Uninstalls a given list of disabled modules.
* *
* @param array $module_list * @param array $module_list
* The modules to uninstall. It is the caller's responsibility to ensure that * The modules to uninstall.
* all modules in this list have already been disabled before this function
* is called.
* @param bool $uninstall_dependents * @param bool $uninstall_dependents
* (optional) If TRUE, the function will check that all modules which depend * (optional) If TRUE, dependent modules will automatically be uninstalled
* on the passed-in module list either are already uninstalled or contained in * in the correct order. This incurs a significant performance cost, so use
* the list, and it will ensure that the modules are uninstalled in the * FALSE if you know $module_list is already complete.
* correct order. This incurs a significant performance cost, so use FALSE if
* you know $module_list is already complete and in the correct order.
* Defaults to TRUE.
* *
* @return bool * @return bool
* Returns TRUE if the operation succeeds or FALSE if it aborts due to an * FALSE if one or more dependencies are missing, TRUE otherwise.
* unsafe condition, namely, $uninstall_dependents is TRUE and a module in *
* $module_list has dependents which are not already uninstalled and not also * @see hook_module_preuninstall()
* included in $module_list). * @see hook_uninstall()
* @see hook_modules_uninstalled()
*/ */
public function uninstall($module_list = array(), $uninstall_dependents = TRUE); public function uninstall(array $module_list, $uninstall_dependents = TRUE);
/** /**
* Returns an array of directories for all enabled modules. Useful for * Returns an array of directories for all enabled modules. Useful for

View File

@ -58,7 +58,7 @@ class UpdateModuleHandler extends ModuleHandler {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function enable($module_list, $enable_dependencies = TRUE) { public function install(array $module_list, $enable_dependencies = TRUE) {
$schema_store = \Drupal::keyValue('system.schema'); $schema_store = \Drupal::keyValue('system.schema');
$old_schema = array(); $old_schema = array();
foreach ($module_list as $module) { foreach ($module_list as $module) {
@ -74,16 +74,13 @@ class UpdateModuleHandler extends ModuleHandler {
db_create_table($table, $spec); db_create_table($table, $spec);
} }
} }
// Enable the module with a weight of 0. // Enable the module with a weight of 0.
$module_config = \Drupal::config('system.module'); $module_config = \Drupal::config('system.module');
$module_config $module_config
->set("enabled.$module", 0) ->set("enabled.$module", 0)
->set('enabled', module_config_sort($module_config->get('enabled'))) ->set('enabled', module_config_sort($module_config->get('enabled')))
->save(); ->save();
// Ensure the module is not contained in disabled modules.
\Drupal::config('system.module.disabled')
->clear($module)
->save();
$current_schema = $schema_store->get($module); $current_schema = $schema_store->get($module);
// Set the schema version if the module was not just disabled before. // Set the schema version if the module was not just disabled before.
@ -105,7 +102,7 @@ class UpdateModuleHandler extends ModuleHandler {
$module_config_path = drupal_get_path('module', $module) . '/config'; $module_config_path = drupal_get_path('module', $module) . '/config';
if (is_dir($module_config_path)) { if (is_dir($module_config_path)) {
$module_filestorage = new FileStorage($module_config_path); $module_filestorage = new FileStorage($module_config_path);
$config_storage = drupal_container()->get('config.storage'); $config_storage = \Drupal::service('config.storage');
foreach ($module_filestorage->listAll() as $config_name) { foreach ($module_filestorage->listAll() as $config_name) {
// If this file already exists, something in the upgrade path went // If this file already exists, something in the upgrade path went
// completely wrong and we want to know. // completely wrong and we want to know.
@ -134,14 +131,7 @@ class UpdateModuleHandler extends ModuleHandler {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function disable($module_list, $disable_dependents = TRUE) { public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
throw new \LogicException('Disabling modules is not supported during updates');
}
/**
* {@inheritdoc}
*/
public function uninstall($module_list = array(), $uninstall_dependents = TRUE) {
throw new \LogicException('Uninstalling modules is not supported during updates'); throw new \LogicException('Uninstalling modules is not supported during updates');
} }

View File

@ -35,7 +35,6 @@ class ActionUninstallTest extends WebTestBase {
* Tests Action uninstall. * Tests Action uninstall.
*/ */
public function testActionUninstall() { public function testActionUninstall() {
\Drupal::moduleHandler()->disable(array('action'));
\Drupal::moduleHandler()->uninstall(array('action')); \Drupal::moduleHandler()->uninstall(array('action'));
$this->assertTrue(entity_load('action', 'user_block_user_action', TRUE), 'Configuration entity \'user_block_user_action\' still exists after uninstalling action module.' ); $this->assertTrue(entity_load('action', 'user_block_user_action', TRUE), 'Configuration entity \'user_block_user_action\' still exists after uninstalling action module.' );

View File

@ -59,7 +59,7 @@ class AggregatorConfigurationTest extends AggregatorTestBase {
// Make sure settings form is still accessible even after disabling a module // Make sure settings form is still accessible even after disabling a module
// that provides the selected plugins. // that provides the selected plugins.
module_disable(array('aggregator_test')); module_uninstall(array('aggregator_test'));
$this->resetAll(); $this->resetAll();
$this->drupalGet('admin/config/services/aggregator/settings'); $this->drupalGet('admin/config/services/aggregator/settings');
$this->assertResponse(200); $this->assertResponse(200);

View File

@ -72,7 +72,7 @@ class UpdateFeedItemTest extends AggregatorTestBase {
// Make sure updating items works even after disabling a module // Make sure updating items works even after disabling a module
// that provides the selected plugins. // that provides the selected plugins.
$this->enableTestPlugins(); $this->enableTestPlugins();
module_disable(array('aggregator_test')); module_uninstall(array('aggregator_test'));
$this->updateFeedItems($feed); $this->updateFeedItems($feed);
$this->assertResponse(200); $this->assertResponse(200);
} }

View File

@ -184,7 +184,7 @@ function block_update_8005() {
* Enable the Custom Block module. * Enable the Custom Block module.
*/ */
function block_update_8006() { function block_update_8006() {
module_enable(array('custom_block')); Drupal::moduleHandler()->install(array('custom_block'));
} }
/** /**

View File

@ -238,7 +238,7 @@ class BlockTest extends BlockTestBase {
* Test _block_rehash(). * Test _block_rehash().
*/ */
function testBlockRehash() { function testBlockRehash() {
module_enable(array('block_test')); \Drupal::moduleHandler()->install(array('block_test'));
$this->assertTrue(module_exists('block_test'), 'Test block module enabled.'); $this->assertTrue(module_exists('block_test'), 'Test block module enabled.');
// Clear the block cache to load the block_test module's block definitions. // Clear the block cache to load the block_test module's block definitions.
@ -267,100 +267,4 @@ class BlockTest extends BlockTestBase {
$this->assertEqual($settings['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE."); $this->assertEqual($settings['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE.");
} }
/**
* Tests blocks belonging to disabled modules.
*/
function testBlockModuleDisable() {
module_enable(array('block_test'));
$this->assertTrue(module_exists('block_test'), 'Test block module enabled.');
// Clear the block cache to load the block_test module's block definitions.
$manager = $this->container->get('plugin.manager.block');
$manager->clearCachedDefinitions();
// Add test blocks in different regions and confirm they are displayed.
$blocks = array();
$regions = array('sidebar_first', 'content', 'footer');
foreach ($regions as $region) {
$blocks[$region] = $this->drupalPlaceBlock('test_cache', array('region' => $region));
}
$this->drupalGet('');
foreach ($regions as $region) {
$this->assertText($blocks[$region]->label());
}
// Disable the block test module and refresh the definitions cache.
module_disable(array('block_test'), FALSE);
$this->assertFalse(module_exists('block_test'), 'Test block module disabled.');
$manager->clearCachedDefinitions();
// Ensure that the block administration page still functions as expected.
$this->drupalGet('admin/structure/block');
$this->assertResponse(200);
// A 200 response is possible with a fatal error, so check the title too.
$this->assertTitle(t('Block layout') . ' | Drupal');
// Ensure that the disabled module's block instance is not listed.
foreach ($regions as $region) {
$this->assertNoText($blocks[$region]->label());
}
// Ensure that the disabled module's block plugin is no longer available.
$this->drupalGet('admin/structure/block/list/' . \Drupal::config('system.theme')->get('default'));
$this->assertNoText(t('Test block caching'));
// Confirm that the block is no longer displayed on the front page.
$this->drupalGet('');
$this->assertResponse(200);
foreach ($regions as $region) {
$this->assertNoText($blocks[$region]->label());
}
// Confirm that a different block instance can still be enabled by
// submitting the block library form.
// Emulate a POST submission rather than using drupalPlaceBlock() to ensure
// that the form still functions as expected.
$edit = array(
'settings[label]' => $this->randomName(8),
'machine_name' => strtolower($this->randomName(8)),
'region' => 'sidebar_first',
);
$this->drupalPostForm('admin/structure/block/add/system_powered_by_block/stark', $edit, t('Save block'));
$this->assertText(t('The block configuration has been saved.'));
$this->assertText($edit['settings[label]']);
// Update the weight of a block.
$edit = array('blocks[stark.' . $edit['machine_name'] . '][weight]' => -1);
$this->drupalPostForm('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'));
// Re-enable the module and refresh the definitions cache.
module_enable(array('block_test'), FALSE);
$this->assertTrue(module_exists('block_test'), 'Test block module re-enabled.');
$manager->clearCachedDefinitions();
// Reload the admin page and confirm the block can again be configured.
$this->drupalGet('admin/structure/block');
foreach ($regions as $region) {
$this->assertLinkByHref(url('admin/structure/block/manage/' . $blocks[$region]->id()));
}
// Confirm that the blocks are again displayed on the front page in the
// correct regions.
$this->drupalGet('');
foreach ($regions as $region) {
// @todo Use a proper method for this.
$name_pieces = explode('.', $blocks[$region]->id());
$machine_name = array_pop($name_pieces);
$xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array(
':region-class' => 'region region-' . drupal_html_class($region),
':block-id' => 'block-' . strtr(strtolower($machine_name), '-', '_'),
));
$this->assertFieldByXPath($xpath, NULL, format_string('Block %name found in the %region region.', array(
'%name' => $blocks[$region]->label(),
'%region' => $region,
)));
}
}
} }

View File

@ -6,15 +6,15 @@
*/ */
/** /**
* Implements hook_enable(). * Implements hook_install().
* *
* Import breakpoints from all enabled themes. * Import breakpoints from all enabled themes.
*/ */
function breakpoint_enable() { function breakpoint_install() {
// Import breakpoints from enabled themes. // Import breakpoints from enabled themes.
$themes = array_filter(list_themes(), function ($theme) {return $theme->status;}); $themes = array_filter(list_themes(), function ($theme) {return $theme->status;});
_breakpoint_theme_enabled(array_keys($themes)); _breakpoint_theme_enabled(array_keys($themes));
// Import breakpoints from modules. // Import breakpoints from modules.
_breakpoint_modules_enabled(array_keys(\Drupal::moduleHandler()->getModuleList())); _breakpoint_modules_installed(array_keys(\Drupal::moduleHandler()->getModuleList()));
} }

View File

@ -62,7 +62,7 @@ function breakpoint_themes_disabled($theme_list) {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_modules_installed().
* *
* @param array $modules * @param array $modules
* An array of the modules that were enabled. * An array of the modules that were enabled.
@ -71,8 +71,8 @@ function breakpoint_themes_disabled($theme_list) {
* *
* @todo: This should be removed if https://drupal.org/node/1813100 is resolved. * @todo: This should be removed if https://drupal.org/node/1813100 is resolved.
*/ */
function breakpoint_modules_enabled($modules) { function breakpoint_modules_installed($modules) {
_breakpoint_modules_enabled($modules); _breakpoint_modules_installed($modules);
} }
/** /**
@ -106,12 +106,12 @@ function _breakpoint_theme_enabled($theme_list) {
} }
/** /**
* Import breakpoints from all new enabled modules. * Import breakpoints from all new installed modules.
* *
* @param array $modules * @param array $modules
* An array of the modules that were enabled. * An array of the modules that were installed.
*/ */
function _breakpoint_modules_enabled($modules) { function _breakpoint_modules_installed($modules) {
foreach ($modules as $module) { foreach ($modules as $module) {
$media_queries = breakpoint_get_module_media_queries($module); $media_queries = breakpoint_get_module_media_queries($module);
_breakpoint_import_media_queries($module, $module, Breakpoint::SOURCE_TYPE_MODULE, $media_queries); _breakpoint_import_media_queries($module, $module, Breakpoint::SOURCE_TYPE_MODULE, $media_queries);

View File

@ -118,10 +118,6 @@ class BreakpointThemeTest extends BreakpointGroupTestBase {
theme_disable(array('breakpoint_test_theme')); theme_disable(array('breakpoint_test_theme'));
$this->assertTrue(entity_load('breakpoint_group', $breakpoint_group_obj->id()), 'Breakpoint group still exists if theme is disabled.'); $this->assertTrue(entity_load('breakpoint_group', $breakpoint_group_obj->id()), 'Breakpoint group still exists if theme is disabled.');
// Disable the test module and verify the breakpoint group still exists.
module_disable(array('breakpoint_theme_test'));
$this->assertTrue(entity_load('breakpoint_group', $breakpoint_group_obj->id()), 'Breakpoint group still exists if module is disabled.');
// Uninstall the test module and verify the breakpoint group is deleted. // Uninstall the test module and verify the breakpoint group is deleted.
module_uninstall(array('breakpoint_theme_test')); module_uninstall(array('breakpoint_theme_test'));
$this->assertFalse(entity_load('breakpoint_group', $breakpoint_group_obj->id()), 'Breakpoint group is removed if module is uninstalled.'); $this->assertFalse(entity_load('breakpoint_group', $breakpoint_group_obj->id()), 'Breakpoint group is removed if module is uninstalled.');

View File

@ -145,7 +145,7 @@ class CKEditorAdminTest extends WebTestBase {
// Now enable the ckeditor_test module, which provides one configurable // Now enable the ckeditor_test module, which provides one configurable
// CKEditor plugin — this should not affect the Editor config entity. // CKEditor plugin — this should not affect the Editor config entity.
module_enable(array('ckeditor_test')); \Drupal::moduleHandler()->install(array('ckeditor_test'));
$this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions(); $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
$this->drupalGet('admin/config/content/formats/manage/filtered_html'); $this->drupalGet('admin/config/content/formats/manage/filtered_html');
$ultra_llama_mode_checkbox = $this->xpath('//input[@type="checkbox" and @name="editor[settings][plugins][llama_contextual_and_button][ultra_llama_mode]" and not(@checked)]'); $ultra_llama_mode_checkbox = $this->xpath('//input[@type="checkbox" and @name="editor[settings][plugins][llama_contextual_and_button][ultra_llama_mode]" and not(@checked)]');

View File

@ -119,7 +119,7 @@ class CKEditorLoadingTest extends WebTestBase {
// NOTE: the tests in CKEditorTest already ensure that changing the // NOTE: the tests in CKEditorTest already ensure that changing the
// configuration also results in modified CKEditor configuration, so we // configuration also results in modified CKEditor configuration, so we
// don't test that here. // don't test that here.
module_enable(array('ckeditor_test')); \Drupal::moduleHandler()->install(array('ckeditor_test'));
$this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions(); $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
$editor->settings['toolbar']['buttons'][0][] = 'Llama'; $editor->settings['toolbar']['buttons'][0][] = 'Llama';
$editor->save(); $editor->save();

View File

@ -17,7 +17,6 @@ function comment_uninstall() {
))); )));
drupal_classloader_register('comment', 'core/modules/comment'); drupal_classloader_register('comment', 'core/modules/comment');
foreach ($node_types as $node_type) { foreach ($node_types as $node_type) {
entity_invoke_bundle_hook('delete', 'comment', 'comment_node_' . $node_type);
variable_del('comment_' . $node_type); variable_del('comment_' . $node_type);
variable_del('comment_anonymous_' . $node_type); variable_del('comment_anonymous_' . $node_type);
variable_del('comment_controls_' . $node_type); variable_del('comment_controls_' . $node_type);
@ -34,9 +33,9 @@ function comment_uninstall() {
} }
/** /**
* Implements hook_enable(). * Implements hook_install().
*/ */
function comment_enable() { function comment_install() {
// Insert records into the node_comment_statistics for nodes that are missing. // Insert records into the node_comment_statistics for nodes that are missing.
$query = db_select('node_field_data', 'n'); $query = db_select('node_field_data', 'n');
$query->leftJoin('node_comment_statistics', 'ncs', 'ncs.nid = n.nid AND n.default_langcode = 1'); $query->leftJoin('node_comment_statistics', 'ncs', 'ncs.nid = n.nid AND n.default_langcode = 1');
@ -53,12 +52,13 @@ function comment_enable() {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_modules_installed().
* *
* Creates comment body fields for node types existing before the Comment module * Creates comment body fields for node types existing before the Comment module
* is enabled. We use hook_modules_enabled() rather than hook_enable() so we can * is enabled. We use hook_modules_installed() rather than hook_install() so we
* react to node types of existing modules, and those of modules being enabled * can react to node types of existing modules, and those of modules being
* both before and after the Comment module in the loop of module_enable(). * enabled both before and after the Comment module in the loop of
* \Drupal\Core\Extension\ModuleHandler::install().
* *
* There is a separate comment bundle for each node type to allow for * There is a separate comment bundle for each node type to allow for
* per-node-type customization of comment fields. Each one of these bundles * per-node-type customization of comment fields. Each one of these bundles
@ -68,7 +68,7 @@ function comment_enable() {
* *
* @see comment_node_type_insert() * @see comment_node_type_insert()
*/ */
function comment_modules_enabled($modules) { function comment_modules_installed($modules) {
// Only react if the Comment module is one of the modules being enabled. // Only react if the Comment module is one of the modules being enabled.
// hook_node_type_insert() is used to create body fields while the comment // hook_node_type_insert() is used to create body fields while the comment
// module is enabled. // module is enabled.

View File

@ -61,31 +61,32 @@ class CommentFieldsTest extends CommentTestBase {
} }
/** /**
* Tests that comment module works when enabled after a content module. * Tests that comment module works when installed after a content module.
*/ */
function testCommentEnable() { function testCommentInstallAfterContentModule() {
// Create a user to do module administration. // Create a user to do module administration.
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules')); $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules'));
$this->drupalLogin($this->admin_user); $this->drupalLogin($this->admin_user);
// Disable the comment module. // Disable the comment module.
$edit = array(); $edit = array();
$edit['modules[Core][comment][enable]'] = FALSE; $edit['uninstall[comment]'] = TRUE;
$this->drupalPostForm('admin/modules', $edit, t('Save configuration')); $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPostForm(NULL, array(), t('Uninstall'));
$this->rebuildContainer(); $this->rebuildContainer();
$this->assertFalse(module_exists('comment'), 'Comment module disabled.'); $this->assertFalse($this->container->get('module_handler')->moduleExists('comment'), 'Comment module uninstalled.');
// Enable core content type module (book). // Enable core content type module (book).
$edit = array(); $edit = array();
$edit['modules[Core][book][enable]'] = 'book'; $edit['modules[Core][book][enable]'] = 'book';
$this->drupalPostForm('admin/modules', $edit, t('Save configuration')); $this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
// Now enable the comment module. // Now install the comment module.
$edit = array(); $edit = array();
$edit['modules[Core][comment][enable]'] = 'comment'; $edit['modules[Core][comment][enable]'] = 'comment';
$this->drupalPostForm('admin/modules', $edit, t('Save configuration')); $this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->rebuildContainer(); $this->rebuildContainer();
$this->assertTrue(module_exists('comment'), 'Comment module enabled.'); $this->assertTrue($this->container->get('module_handler')->moduleExists('comment'), 'Comment module enabled.');
// Create nodes of each type. // Create nodes of each type.
$book_node = $this->drupalCreateNode(array('type' => 'book')); $book_node = $this->drupalCreateNode(array('type' => 'book'));

View File

@ -46,7 +46,6 @@ class CommentUninstallTest extends WebTestBase {
$this->assertNotNull($field, 'The comment_body field exists.'); $this->assertNotNull($field, 'The comment_body field exists.');
// Uninstall the comment module which should trigger field deletion. // Uninstall the comment module which should trigger field deletion.
$this->container->get('module_handler')->disable(array('comment'));
$this->container->get('module_handler')->uninstall(array('comment')); $this->container->get('module_handler')->uninstall(array('comment'));
// Check that the field is now deleted. // Check that the field is now deleted.
@ -70,7 +69,6 @@ class CommentUninstallTest extends WebTestBase {
// Ensure that uninstallation succeeds even if the field has already been // Ensure that uninstallation succeeds even if the field has already been
// deleted manually beforehand. // deleted manually beforehand.
$this->container->get('module_handler')->disable(array('comment'));
$this->container->get('module_handler')->uninstall(array('comment')); $this->container->get('module_handler')->uninstall(array('comment'));
} }

View File

@ -37,7 +37,7 @@ class ConfigInstallWebTest extends WebTestBase {
$default_configuration_entity = 'config_test.dynamic.config_integration_test'; $default_configuration_entity = 'config_test.dynamic.config_integration_test';
// Install the config_test module we're integrating with. // Install the config_test module we're integrating with.
module_enable(array('config_test')); \Drupal::moduleHandler()->install(array('config_test'));
// Verify the configuration does not exist prior to installation. // Verify the configuration does not exist prior to installation.
$config_static = \Drupal::config($default_config); $config_static = \Drupal::config($default_config);
@ -46,7 +46,7 @@ class ConfigInstallWebTest extends WebTestBase {
$this->assertIdentical($config_entity->isNew(), TRUE); $this->assertIdentical($config_entity->isNew(), TRUE);
// Install the integration module. // Install the integration module.
module_enable(array('config_integration_test')); \Drupal::moduleHandler()->install(array('config_integration_test'));
// Verify that default module config exists. // Verify that default module config exists.
$config_static = \Drupal::config($default_config); $config_static = \Drupal::config($default_config);
@ -66,20 +66,7 @@ class ConfigInstallWebTest extends WebTestBase {
// In other words: This test passes even without this reset, but it shouldn't. // In other words: This test passes even without this reset, but it shouldn't.
$this->container->get('config.factory')->reset(); $this->container->get('config.factory')->reset();
// Disable and enable the integration module.
module_disable(array('config_integration_test'));
module_enable(array('config_integration_test'));
// Verify that customized config exists.
$config_static = \Drupal::config($default_config);
$this->assertIdentical($config_static->isNew(), FALSE);
$this->assertIdentical($config_static->get('foo'), 'customized setting');
$config_entity = \Drupal::config($default_configuration_entity);
$this->assertIdentical($config_entity->isNew(), FALSE);
$this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
// Disable and uninstall the integration module. // Disable and uninstall the integration module.
module_disable(array('config_integration_test'));
module_uninstall(array('config_integration_test')); module_uninstall(array('config_integration_test'));
// Verify the integration module's config was uninstalled. // Verify the integration module's config was uninstalled.
@ -92,7 +79,7 @@ class ConfigInstallWebTest extends WebTestBase {
$this->assertIdentical($config_entity->get('label'), 'Customized integration config label'); $this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
// Reinstall the integration module. // Reinstall the integration module.
module_enable(array('config_integration_test')); \Drupal::moduleHandler()->install(array('config_integration_test'));
// Verify the integration module's config was re-installed. // Verify the integration module's config was re-installed.
$config_static = \Drupal::config($default_config); $config_static = \Drupal::config($default_config);

View File

@ -39,7 +39,7 @@ class ConfigOtherModuleTest extends WebTestBase {
* Tests enabling the provider of the default configuration first. * Tests enabling the provider of the default configuration first.
*/ */
public function testInstallOtherModuleFirst() { public function testInstallOtherModuleFirst() {
$this->moduleHandler->enable(array('config_other_module_config')); $this->moduleHandler->install(array('config_other_module_config'));
// Check that the config entity doesn't exist before the config_test module // Check that the config entity doesn't exist before the config_test module
// is enabled. We cannot use the entity system because the config_test // is enabled. We cannot use the entity system because the config_test
@ -49,19 +49,18 @@ class ConfigOtherModuleTest extends WebTestBase {
// Install the module that provides the entity type. This installs the // Install the module that provides the entity type. This installs the
// default configuration. // default configuration.
$this->moduleHandler->enable(array('config_test')); $this->moduleHandler->install(array('config_test'));
$this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration has been installed.'); $this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration has been installed.');
// Uninstall the module that provides the entity type. This will remove the // Uninstall the module that provides the entity type. This will remove the
// default configuration. // default configuration.
$this->moduleHandler->disable(array('config_test'));
$this->moduleHandler->uninstall(array('config_test')); $this->moduleHandler->uninstall(array('config_test'));
$config = $this->container->get('config.factory')->get('config_test.dynamic.other_module'); $config = $this->container->get('config.factory')->get('config_test.dynamic.other_module');
$this->assertTrue($config->isNew(), 'Default configuration for other modules is removed when the config entity provider is disabled.'); $this->assertTrue($config->isNew(), 'Default configuration for other modules is removed when the config entity provider is disabled.');
// Install the module that provides the entity type again. This installs the // Install the module that provides the entity type again. This installs the
// default configuration. // default configuration.
$this->moduleHandler->enable(array('config_test')); $this->moduleHandler->install(array('config_test'));
$other_module_config_entity = entity_load('config_test', 'other_module', TRUE); $other_module_config_entity = entity_load('config_test', 'other_module', TRUE);
$this->assertTrue($other_module_config_entity, "Default configuration has been recreated."); $this->assertTrue($other_module_config_entity, "Default configuration has been recreated.");
@ -71,7 +70,6 @@ class ConfigOtherModuleTest extends WebTestBase {
$other_module_config_entity->save(); $other_module_config_entity->save();
// Uninstall the module that provides the default configuration. // Uninstall the module that provides the default configuration.
$this->moduleHandler->disable(array('config_other_module_config'));
$this->moduleHandler->uninstall(array('config_other_module_config')); $this->moduleHandler->uninstall(array('config_other_module_config'));
$this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration for other modules is not removed when the module that provides it is uninstalled.'); $this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration for other modules is not removed when the module that provides it is uninstalled.');
@ -79,7 +77,7 @@ class ConfigOtherModuleTest extends WebTestBase {
$this->assertTrue(entity_load('config_test', 'dotted.default', TRUE), 'The configuration is not deleted.'); $this->assertTrue(entity_load('config_test', 'dotted.default', TRUE), 'The configuration is not deleted.');
// Re-enable module to test that default config is unchanged. // Re-enable module to test that default config is unchanged.
$this->moduleHandler->enable(array('config_other_module_config')); $this->moduleHandler->install(array('config_other_module_config'));
$config_entity = entity_load('config_test', 'other_module', TRUE); $config_entity = entity_load('config_test', 'other_module', TRUE);
$this->assertEqual($config_entity->get('style'), "The piano ain't got no wrong notes.", 'Re-enabling the module does not install default config over the existing config entity.'); $this->assertEqual($config_entity->get('style'), "The piano ain't got no wrong notes.", 'Re-enabling the module does not install default config over the existing config entity.');
} }
@ -88,10 +86,10 @@ class ConfigOtherModuleTest extends WebTestBase {
* Tests enabling the provider of the config entity type first. * Tests enabling the provider of the config entity type first.
*/ */
public function testInstallConfigEnityModuleFirst() { public function testInstallConfigEnityModuleFirst() {
$this->moduleHandler->enable(array('config_test')); $this->moduleHandler->install(array('config_test'));
$this->assertFalse(entity_load('config_test', 'other_module', TRUE), 'Default configuration provided by config_other_module_config does not exist.'); $this->assertFalse(entity_load('config_test', 'other_module', TRUE), 'Default configuration provided by config_other_module_config does not exist.');
$this->moduleHandler->enable(array('config_other_module_config')); $this->moduleHandler->install(array('config_other_module_config'));
$this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration provided by config_other_module_config has been installed.'); $this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration provided by config_other_module_config has been installed.');
} }

View File

@ -104,7 +104,7 @@ class EditorAdminTest extends WebTestBase {
* Enables the unicorn editor. * Enables the unicorn editor.
*/ */
protected function enableUnicornEditor() { protected function enableUnicornEditor() {
module_enable(array('editor_test')); \Drupal::moduleHandler()->install(array('editor_test'));
$this->rebuildContainer(); $this->rebuildContainer();
$this->resetAll(); $this->resetAll();
} }

View File

@ -156,3 +156,18 @@ function entity_entity_bundle_delete($entity_type, $bundle) {
} }
entity_delete_multiple('entity_form_display', $ids); entity_delete_multiple('entity_form_display', $ids);
} }
/**
* Implements hook_module_preuninstall().
*/
function entity_module_preuninstall($module) {
// Clean up all entity bundles (including field instances) of every entity
// type provided by the module that is being uninstalled.
foreach (Drupal::entityManager()->getDefinitions() as $entity_type => $entity_info) {
if ($entity_info['module'] == $module) {
foreach (array_keys(entity_get_bundles($entity_type)) as $bundle) {
entity_invoke_bundle_hook('delete', $entity_type, $bundle);
}
}
}
}

View File

@ -337,17 +337,17 @@ function field_rebuild() {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_modules_installed().
*/ */
function field_modules_enabled($modules) { function field_modules_installed($modules) {
// Refresh the 'active' status of fields. // Refresh the 'active' status of fields.
field_sync_field_status(); field_sync_field_status();
} }
/** /**
* Implements hook_modules_disabled(). * Implements hook_modules_uninstalled().
*/ */
function field_modules_disabled($modules) { function field_modules_uninstalled($modules) {
// Refresh the 'active' status of fields. // Refresh the 'active' status of fields.
field_sync_field_status(); field_sync_field_status();
} }

View File

@ -1,55 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\field\Tests\ActiveTest.
*/
namespace Drupal\field\Tests;
class ActiveTest extends FieldTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('field_test', 'entity_test');
public static function getInfo() {
return array(
'name' => 'Field active test',
'description' => 'Test that fields are properly marked active or inactive.',
'group' => 'Field API',
);
}
/**
* Test that fields are properly marked active or inactive.
*/
function testActive() {
$field_name = 'field_1';
entity_create('field_entity', array(
'name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'test_field',
))->save();
// Check that the field is correctly found.
$field = field_read_field('entity_test', $field_name);
$this->assertFalse(empty($field), 'The field was properly read.');
// Disable the module providing the field type, and check that the field is
// found only if explicitly requesting inactive fields.
module_disable(array('field_test'));
$field = field_read_field('entity_test', $field_name);
$this->assertTrue(empty($field), 'The field is marked inactive when the field type is absent.');
$field = field_read_field('entity_test', $field_name, array('include_inactive' => TRUE));
$this->assertFalse(empty($field), 'The field is properly read when explicitly fetching inactive fields.');
// Re-enable the module, and check that the field is active again.
module_enable(array('field_test'));
$field = field_read_field('entity_test', $field_name);
$this->assertFalse(empty($field), 'The field was was marked active.');
}
}

View File

@ -46,7 +46,7 @@ class FieldImportCreateTest extends FieldUnitTestBase {
// Enable field_test_config module and check that the field and instance // Enable field_test_config module and check that the field and instance
// shipped in the module's default config were created. // shipped in the module's default config were created.
module_enable(array('field_test_config')); \Drupal::moduleHandler()->install(array('field_test_config'));
// A field with one instance. // A field with one instance.
$field = entity_load('field_entity', $field_id); $field = entity_load('field_entity', $field_id);

View File

@ -191,7 +191,7 @@ class FieldInfoTest extends FieldUnitTestBase {
entity_create('field_instance', $instance_definition); entity_create('field_instance', $instance_definition);
// Disable coment module. This clears field_info cache. // Disable coment module. This clears field_info cache.
module_disable(array('comment')); module_uninstall(array('comment'));
$this->assertNull(field_info_instance('comment', 'field', 'comment_node_article'), 'No instances are returned on disabled entity types.'); $this->assertNull(field_info_instance('comment', 'field', 'comment_node_article'), 'No instances are returned on disabled entity types.');
} }

View File

@ -91,15 +91,7 @@ class reEnableModuleFieldTest extends WebTestBase {
$this->drupalPostForm(NULL, $edit, t('Save')); $this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw('<a href="tel:123456789">'); $this->assertRaw('<a href="tel:123456789">');
// Disable the telephone module and re-enable it. // Test that the module can't be uninstalled from the UI while there is data
module_disable(array('telephone'));
module_enable(array('telephone'));
// Display the article creation form and verify the widget still exists.
$this->drupalGet('node/add/article');
$this->assertFieldByName("field_telephone[0][value]", '', 'Widget found.');
// Test that the module can't be disabled from the UI while there is data
// for it's fields. // for it's fields.
$admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules')); $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules'));
$this->drupalLogin($admin_user); $this->drupalLogin($admin_user);

View File

@ -17,12 +17,7 @@ function forum_install() {
$locked = \Drupal::state()->get('node.type.locked'); $locked = \Drupal::state()->get('node.type.locked');
$locked['forum'] = 'forum'; $locked['forum'] = 'forum';
\Drupal::state()->set('node.type.locked', $locked); \Drupal::state()->set('node.type.locked', $locked);
}
/**
* Implements hook_enable().
*/
function forum_enable() {
// Create the forum vocabulary if it does not exist. // Create the forum vocabulary if it does not exist.
// @todo Change Forum module so forum.settings can contain the vocabulary's // @todo Change Forum module so forum.settings can contain the vocabulary's
// machine name. // machine name.
@ -112,11 +107,11 @@ function forum_enable() {
} }
/** /**
* Implements hook_modules_preinstall(). * Implements hook_module_preinstall().
*/ */
function forum_modules_preinstall($modules) { function forum_module_preinstall($module) {
$list_boolean = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinition('list_boolean'); $list_boolean = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinition('list_boolean');
if (empty($list_boolean) && in_array('forum', $modules)) { if (empty($list_boolean) && $module == 'forum') {
// Make sure that the list_boolean field type is available before our // Make sure that the list_boolean field type is available before our
// default config is installed. // default config is installed.
field_info_cache_clear(); field_info_cache_clear();

View File

@ -105,30 +105,6 @@ class ForumTest extends WebTestBase {
)); ));
} }
/**
* Tests disabling and re-enabling the Forum module.
*/
function testEnableForumField() {
$this->drupalLogin($this->admin_user);
// Disable the Forum module.
$edit = array();
$edit['modules[Core][forum][enable]'] = FALSE;
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
$this->rebuildContainer();
$this->assertFalse(module_exists('forum'), 'Forum module is not enabled.');
// Attempt to re-enable the Forum module and ensure it does not try to
// recreate the taxonomy_forums field.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
$this->rebuildContainer();
$this->assertTrue(module_exists('forum'), 'Forum module is enabled.');
}
/** /**
* Tests forum functionality through the admin and user interfaces. * Tests forum functionality through the admin and user interfaces.
*/ */
@ -253,7 +229,7 @@ class ForumTest extends WebTestBase {
$this->assertEqual(0, $nid_count, 'A forum node was not created when missing a forum vocabulary.'); $this->assertEqual(0, $nid_count, 'A forum node was not created when missing a forum vocabulary.');
// Reset the defaults for future tests. // Reset the defaults for future tests.
module_enable(array('forum')); \Drupal::moduleHandler()->install(array('forum'));
} }
/** /**

View File

@ -38,7 +38,6 @@ class ForumUninstallTest extends WebTestBase {
$this->assertNotNull($field, 'The taxonomy_forums field exists.'); $this->assertNotNull($field, 'The taxonomy_forums field exists.');
// Uninstall the forum module which should trigger field deletion. // Uninstall the forum module which should trigger field deletion.
$this->container->get('module_handler')->disable(array('forum'));
$this->container->get('module_handler')->uninstall(array('forum')); $this->container->get('module_handler')->uninstall(array('forum'));
// Check that the field is now deleted. // Check that the field is now deleted.
@ -62,7 +61,6 @@ class ForumUninstallTest extends WebTestBase {
// Ensure that uninstallation succeeds even if the field has already been // Ensure that uninstallation succeeds even if the field has already been
// deleted manually beforehand. // deleted manually beforehand.
$this->container->get('module_handler')->disable(array('forum'));
$this->container->get('module_handler')->uninstall(array('forum')); $this->container->get('module_handler')->uninstall(array('forum'));
} }

View File

@ -21,6 +21,9 @@ function language_install() {
module_load_include('inc', 'language', 'language.negotiation'); module_load_include('inc', 'language', 'language.negotiation');
language_negotiation_set($type, array(LANGUAGE_NEGOTIATION_URL => 0)); language_negotiation_set($type, array(LANGUAGE_NEGOTIATION_URL => 0));
} }
// Update the language count.
language_update_count();
} }
/** /**
@ -44,24 +47,10 @@ function language_uninstall() {
// Re-initialize the language system so successive calls to t() and other // Re-initialize the language system so successive calls to t() and other
// functions will not expect languages to be present. // functions will not expect languages to be present.
drupal_language_initialize(); drupal_language_initialize();
}
/** // Force the language_count state to be 1, so that when checking if the
* Implements hook_enable().
*/
function language_enable() {
// Update the language count, if the module was disabled before, the
// language_count state was forced to 1.
language_update_count();
}
/**
* Implements hook_disable().
*/
function language_disable() {
// Force the language_count state to be 1, so that the when checking if the
// site is multilingual (for example in language_multilingual()), the result // site is multilingual (for example in language_multilingual()), the result
// will be FALSE, because the language module is disabled. // will be FALSE, because the language module is not installed.
\Drupal::state()->set('language_count', 1); \Drupal::state()->set('language_count', 1);
} }

View File

@ -714,9 +714,9 @@ function language_negotiation_include() {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_modules_installed().
*/ */
function language_modules_enabled($modules) { function language_modules_installed($modules) {
include_once DRUPAL_ROOT . '/core/includes/language.inc'; include_once DRUPAL_ROOT . '/core/includes/language.inc';
// Load configurability options from configuration. // Load configurability options from configuration.
language_types_set(array()); language_types_set(array());
@ -724,10 +724,10 @@ function language_modules_enabled($modules) {
} }
/** /**
* Implements hook_modules_disabled(). * Implements hook_modules_uninstalled().
*/ */
function language_modules_disabled($modules) { function language_modules_uninstalled($modules) {
language_modules_enabled($modules); language_modules_installed($modules);
} }
/** /**

View File

@ -102,9 +102,9 @@ class LanguageNegotiationInfoTest extends WebTestBase {
$this->assertEqual($langcode, $value, format_string('The negotiated language for %type is %language', array('%type' => $type, '%language' => $value))); $this->assertEqual($langcode, $value, format_string('The negotiated language for %type is %language', array('%type' => $type, '%language' => $value)));
} }
// Disable language_test and check that everything is set back to the // Uninstall language_test and check that everything is set back to the
// original status. // original status.
$this->languageNegotiationUpdate('disable'); $this->languageNegotiationUpdate('uninstall');
// Check that only the core language types are available. // Check that only the core language types are available.
foreach (language_types_get_all() as $type) { foreach (language_types_get_all() as $type) {
@ -128,25 +128,24 @@ class LanguageNegotiationInfoTest extends WebTestBase {
/** /**
* Update language types/negotiation information. * Update language types/negotiation information.
* *
* Manually invoke language_modules_enabled()/language_modules_disabled() * Manually invoke language_modules_installed()/language_modules_uninstalled()
* since they would not be invoked after enabling/disabling language_test the * since they would not be invoked after installing/uninstalling language_test
* first time. * the first time.
*/ */
protected function languageNegotiationUpdate($op = 'enable') { protected function languageNegotiationUpdate($op = 'install') {
static $last_op = NULL; static $last_op = NULL;
$modules = array('language_test'); $modules = array('language_test');
// Enable/disable language_test only if we did not already before. // Install/uninstall language_test only if we did not already before.
if ($last_op != $op) { if ($last_op != $op) {
$function = "module_{$op}"; call_user_func(array($this->container->get('module_handler'), $op), $modules);
$function($modules);
// Reset hook implementation cache. // Reset hook implementation cache.
$this->container->get('module_handler')->resetImplementations(); $this->container->get('module_handler')->resetImplementations();
} }
drupal_static_reset('language_types_info'); drupal_static_reset('language_types_info');
drupal_static_reset('language_negotiation_info'); drupal_static_reset('language_negotiation_info');
$function = "language_modules_{$op}d"; $function = "language_modules_{$op}ed";
if (function_exists($function)) { if (function_exists($function)) {
$function($modules); $function($modules);
} }

View File

@ -138,8 +138,7 @@ class LocaleConfigTranslationTest extends WebTestBase {
// Quick test to ensure translation file exists. // Quick test to ensure translation file exists.
$this->assertEqual(\Drupal::config('locale.config.xx.image.style.medium')->get('label'), $image_style_label); $this->assertEqual(\Drupal::config('locale.config.xx.image.style.medium')->get('label'), $image_style_label);
// Disable and uninstall the module. // Uninstall the module.
$this->drupalPostForm('admin/modules', array('modules[Core][image][enable]' => FALSE), t('Save configuration'));
$this->drupalPostForm('admin/modules/uninstall', array('uninstall[image]' => "image"), t('Uninstall')); $this->drupalPostForm('admin/modules/uninstall', array('uninstall[image]' => "image"), t('Uninstall'));
$this->drupalPostForm(NULL, array(), t('Uninstall')); $this->drupalPostForm(NULL, array(), t('Uninstall'));

View File

@ -214,7 +214,7 @@ class LocaleContentTest extends WebTestBase {
* Test filtering Node content by language. * Test filtering Node content by language.
*/ */
function testNodeAdminLanguageFilter() { function testNodeAdminLanguageFilter() {
module_enable(array('views')); \Drupal::moduleHandler()->install(array('views'));
// User to add and remove language. // User to add and remove language.
$admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access')); $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access'));

View File

@ -109,7 +109,6 @@ class LocaleUninstallTest extends WebTestBase {
->save(); ->save();
// Uninstall Locale. // Uninstall Locale.
module_disable($locale_module);
module_uninstall($locale_module); module_uninstall($locale_module);
$this->rebuildContainer(); $this->rebuildContainer();

View File

@ -332,7 +332,7 @@ class LocaleUpdateTest extends LocaleUpdateBase {
/** /**
* Tests automatic translation import when a module is enabled. * Tests automatic translation import when a module is enabled.
*/ */
function testEnableDisableModule() { function testEnableUninstallModule() {
// Make the hidden test modules look like a normal custom module. // Make the hidden test modules look like a normal custom module.
\Drupal::state()->set('locale.test_system_info_alter', TRUE); \Drupal::state()->set('locale.test_system_info_alter', TRUE);
@ -350,11 +350,6 @@ class LocaleUpdateTest extends LocaleUpdateBase {
array('%number' => 7, '%update' => 0, '%delete' => 0)), 'One translation file imported.'); array('%number' => 7, '%update' => 0, '%delete' => 0)), 'One translation file imported.');
$this->assertTranslation('Tuesday', 'Dienstag', 'de'); $this->assertTranslation('Tuesday', 'Dienstag', 'de');
// Disable and uninstall a module.
$edit = array(
'modules[Testing][locale_test_translate][enable]' => FALSE,
);
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$edit = array( $edit = array(
'uninstall[locale_test_translate]' => 1, 'uninstall[locale_test_translate]' => 1,
); );
@ -375,7 +370,7 @@ class LocaleUpdateTest extends LocaleUpdateBase {
* enabled modules and will import them. When a language is removed the system * enabled modules and will import them. When a language is removed the system
* will remove all translations of that langugue from the database. * will remove all translations of that langugue from the database.
*/ */
function testEnableDisableLanguage() { function testEnableLanguage() {
// Make the hidden test modules look like a normal custom module. // Make the hidden test modules look like a normal custom module.
\Drupal::state()->set('locale.test_system_info_alter', TRUE); \Drupal::state()->set('locale.test_system_info_alter', TRUE);

View File

@ -33,7 +33,6 @@ class MenuUninstallTest extends WebTestBase {
* Tests Menu uninstall. * Tests Menu uninstall.
*/ */
public function testMenuUninstall() { public function testMenuUninstall() {
\Drupal::moduleHandler()->disable(array('menu'));
\Drupal::moduleHandler()->uninstall(array('menu')); \Drupal::moduleHandler()->uninstall(array('menu'));
$this->assertTrue(entity_load('menu', 'admin', TRUE), 'The \'admin\' menu still exists after uninstalling menu module.'); $this->assertTrue(entity_load('menu', 'admin', TRUE), 'The \'admin\' menu still exists after uninstalling menu module.');

View File

@ -7,6 +7,41 @@
use Drupal\Component\Uuid\Uuid; use Drupal\Component\Uuid\Uuid;
/**
* Implements hook_install().
*/
function menu_install() {
// Add a link for each custom menu.
Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
$system_link = entity_load_multiple_by_properties('menu_link', array('link_path' => 'admin/structure/menu', 'module' => 'system'));
$system_link = reset($system_link);
$base_link = entity_create('menu_link', array(
'menu_name' => $system_link->menu_name,
'router_path' => 'admin/structure/menu/manage/%',
'module' => 'menu',
));
$menus = entity_load_multiple('menu');
foreach ($menus as $menu) {
$link = $base_link->createDuplicate();
$link->plid = $system_link->id();
$link->link_title = $menu->label();
$link->link_path = 'admin/structure/menu/manage/' . $menu->id();
$query = Drupal::entityQuery('menu_link')
->condition('link_path', $link->link_path)
->condition('plid', $link->plid);
$result = $query->execute();
if (empty($result)) {
$link->save();
}
}
menu_cache_clear_all();
}
/** /**
* Implements hook_uninstall(). * Implements hook_uninstall().
*/ */

View File

@ -172,42 +172,6 @@ function menu_theme() {
); );
} }
/**
* Implements hook_enable().
*
* Add a link for each custom menu.
*/
function menu_enable() {
\Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
$system_link = entity_load_multiple_by_properties('menu_link', array('link_path' => 'admin/structure/menu', 'module' => 'system'));
$system_link = reset($system_link);
$base_link = entity_create('menu_link', array(
'menu_name' => $system_link->menu_name,
'router_path' => 'admin/structure/menu/manage/%menu',
'module' => 'menu',
));
$menus = entity_load_multiple('menu');
foreach ($menus as $menu) {
$link = $base_link->createDuplicate();
$link->plid = $system_link->id();
$link->link_title = $menu->label();
$link->link_path = 'admin/structure/menu/manage/' . $menu->id();
$query = \Drupal::entityQuery('menu_link')
->condition('link_path', $link->link_path)
->condition('plid', $link->plid);
$result = $query->execute();
if (empty($result)) {
$link->save();
}
}
menu_cache_clear_all();
}
/** /**
* Load the data for a single custom menu. * Load the data for a single custom menu.
* *

View File

@ -52,7 +52,7 @@ class NodeImportCreateTest extends DrupalUnitTestBase {
// Enable node_test_config module and check that the content type // Enable node_test_config module and check that the content type
// shipped in the module's default config is created. // shipped in the module's default config is created.
$this->container->get('module_handler')->enable(array('node_test_config')); $this->container->get('module_handler')->install(array('node_test_config'));
$node_type = entity_load('node_type', $node_type_id); $node_type = entity_load('node_type', $node_type_id);
$this->assertTrue($node_type, 'The default content type was created.'); $this->assertTrue($node_type, 'The default content type was created.');
} }

View File

@ -49,7 +49,7 @@ class NodeAdminTest extends NodeTestBase {
// Create nodes that have different node.changed values. // Create nodes that have different node.changed values.
$this->container->get('state')->set('node_test.storage_controller', TRUE); $this->container->get('state')->set('node_test.storage_controller', TRUE);
module_enable(array('node_test')); \Drupal::moduleHandler()->install(array('node_test'));
$changed = REQUEST_TIME; $changed = REQUEST_TIME;
foreach (array('dd', 'aa', 'DD', 'bb', 'cc', 'CC', 'AA', 'BB') as $prefix) { foreach (array('dd', 'aa', 'DD', 'bb', 'cc', 'CC', 'AA', 'BB') as $prefix) {
$changed += 1000; $changed += 1000;

View File

@ -50,24 +50,7 @@ class NodeTypePersistenceTest extends NodeTestBase {
$this->drupalGet('node/add'); $this->drupalGet('node/add');
$this->assertText($description, 'Customized description found'); $this->assertText($description, 'Customized description found');
// Disable forum and check that the node type gets disabled. // Uninstall forum.
$this->drupalPostForm('admin/modules', $forum_disable, t('Save configuration'));
$forum = entity_load('node_type', 'forum');
$this->assertTrue($forum->isLocked(), 'Forum node type is node locked');
$this->drupalGet('node/add');
$this->assertNoText('forum', 'forum type is not found on node/add');
// Reenable forum and check that the customization survived the module
// disable.
$this->drupalPostForm('admin/modules', $forum_enable, t('Save configuration'));
$forum = entity_load('node_type', 'forum');
$this->assertTrue($forum->id(), 'Forum node type found.');
$this->assertTrue($forum->isLocked(), 'Forum node type is locked');
$this->drupalGet('node/add');
$this->assertText($description, 'Customized description found');
// Disable and uninstall forum.
$this->drupalPostForm('admin/modules', $forum_disable, t('Save configuration'));
$edit = array('uninstall[forum]' => 'forum'); $edit = array('uninstall[forum]' => 'forum');
$this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall')); $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPostForm(NULL, array(), t('Uninstall')); $this->drupalPostForm(NULL, array(), t('Uninstall'));

View File

@ -134,7 +134,7 @@ class NodeTypeTest extends NodeTestBase {
*/ */
function testNodeTypeStatus() { function testNodeTypeStatus() {
// Enable all core node modules, and all types should be active. // Enable all core node modules, and all types should be active.
$this->container->get('module_handler')->enable(array('book'), FALSE); $this->container->get('module_handler')->install(array('book'), FALSE);
$types = node_type_get_types(); $types = node_type_get_types();
foreach (array('book', 'article', 'page') as $type) { foreach (array('book', 'article', 'page') as $type) {
$this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type))); $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type)));
@ -143,14 +143,14 @@ class NodeTypeTest extends NodeTestBase {
// Disable book module and the respective type should still be active, since // Disable book module and the respective type should still be active, since
// it is not provided by shipped configuration entity. // it is not provided by shipped configuration entity.
$this->container->get('module_handler')->disable(array('book'), FALSE); $this->container->get('module_handler')->uninstall(array('book'), FALSE);
$types = node_type_get_types(); $types = node_type_get_types();
$this->assertFalse($types['book']->isLocked(), "Book module's node type still active."); $this->assertFalse($types['book']->isLocked(), "Book module's node type still active.");
$this->assertFalse($types['article']->isLocked(), 'Article node type still active.'); $this->assertFalse($types['article']->isLocked(), 'Article node type still active.');
$this->assertFalse($types['page']->isLocked(), 'Basic page node type still active.'); $this->assertFalse($types['page']->isLocked(), 'Basic page node type still active.');
// Re-enable the modules and verify that the types are active again. // Re-install the modules and verify that the types are active again.
$this->container->get('module_handler')->enable(array('book'), FALSE); $this->container->get('module_handler')->install(array('book'), FALSE);
$types = node_type_get_types(); $types = node_type_get_types();
foreach (array('book', 'article', 'page') as $type) { foreach (array('book', 'article', 'page') as $type) {
$this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type))); $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type)));
@ -192,10 +192,9 @@ class NodeTypeTest extends NodeTestBase {
); );
$this->assertText(t('This action cannot be undone.'), 'The node type deletion confirmation form is available.'); $this->assertText(t('This action cannot be undone.'), 'The node type deletion confirmation form is available.');
// Test that forum node type could not be deleted while forum active. // Test that forum node type could not be deleted while forum active.
$this->container->get('module_handler')->enable(array('forum')); $this->container->get('module_handler')->install(array('forum'));
$this->drupalGet('admin/structure/types/manage/forum/delete'); $this->drupalGet('admin/structure/types/manage/forum/delete');
$this->assertResponse(403); $this->assertResponse(403);
$this->container->get('module_handler')->disable(array('forum'));
$this->container->get('module_handler')->uninstall(array('forum')); $this->container->get('module_handler')->uninstall(array('forum'));
$this->drupalGet('admin/structure/types/manage/forum/delete'); $this->drupalGet('admin/structure/types/manage/forum/delete');
$this->assertResponse(200); $this->assertResponse(200);

View File

@ -696,7 +696,7 @@ function node_update_8011() {
*/ */
function node_update_8012() { function node_update_8012() {
// Enable the history module without re-installing the schema. // Enable the history module without re-installing the schema.
module_enable(array('history')); Drupal::moduleHandler()->install(array('history'));
} }
/** /**

View File

@ -1275,27 +1275,6 @@ function node_form_block_form_alter(&$form, &$form_state) {
); );
} }
/**
* Implements hook_modules_uninstalled().
*/
function node_modules_uninstalled($modules) {
// Remove module-specific settings from all node types.
$config_names = config_get_storage_names_with_prefix('node.type.');
foreach ($config_names as $config_name) {
$config = \Drupal::config($config_name);
$changed = FALSE;
foreach ($modules as $module) {
if ($config->get('settings.' . $module)) {
$config->clear('settings.' . $module);
$changed = TRUE;
}
}
if ($changed) {
$config->save();
}
}
}
/** /**
* Implements hook_block_access(). * Implements hook_block_access().
* *
@ -1937,7 +1916,7 @@ function node_access_needs_rebuild($rebuild = NULL) {
* rebuild only once he is done. * rebuild only once he is done.
* *
* Note : As of Drupal 6, node access modules are not required to (and actually * Note : As of Drupal 6, node access modules are not required to (and actually
* should not) call node_access_rebuild() in hook_enable/disable anymore. * should not) call node_access_rebuild() in hook_install/uninstall anymore.
* *
* @param $batch_mode * @param $batch_mode
* (optional) Set to TRUE to process in 'batch' mode, spawning processing over * (optional) Set to TRUE to process in 'batch' mode, spawning processing over
@ -2089,9 +2068,9 @@ function node_requirements($phase) {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_modules_installed().
*/ */
function node_modules_enabled($modules) { function node_modules_installed($modules) {
// Check if any of the newly enabled modules require the node_access table to // Check if any of the newly enabled modules require the node_access table to
// be rebuilt. // be rebuilt.
if (!node_access_needs_rebuild() && array_intersect($modules, \Drupal::moduleHandler()->getImplementations('node_grants'))) { if (!node_access_needs_rebuild() && array_intersect($modules, \Drupal::moduleHandler()->getImplementations('node_grants'))) {
@ -2100,9 +2079,25 @@ function node_modules_enabled($modules) {
} }
/** /**
* Implements hook_modules_disabled(). * Implements hook_modules_uninstalled().
*/ */
function node_modules_disabled($modules) { function node_modules_uninstalled($modules) {
// Remove module-specific settings from all node types.
$config_names = config_get_storage_names_with_prefix('node.type.');
foreach ($config_names as $config_name) {
$config = config($config_name);
$changed = FALSE;
foreach ($modules as $module) {
if ($config->get('settings.' . $module)) {
$config->clear('settings.' . $module);
$changed = TRUE;
}
}
if ($changed) {
$config->save();
}
}
// Check whether any of the disabled modules implemented hook_node_grants(), // Check whether any of the disabled modules implemented hook_node_grants(),
// in which case the node access table needs to be rebuilt. // in which case the node access table needs to be rebuilt.
foreach ($modules as $module) { foreach ($modules as $module) {
@ -2199,7 +2194,7 @@ function node_library_info() {
*/ */
function node_system_info_alter(&$info, $file, $type) { function node_system_info_alter(&$info, $file, $type) {
if ($type == 'module' && $file->name == 'translation') { if ($type == 'module' && $file->name == 'translation') {
$info['hidden'] = !module_exists('translation') && \Drupal::config('system.module.disabled')->get('translation') === NULL; $info['hidden'] = !module_exists('translation');
} }
} }

View File

@ -0,0 +1,43 @@
<?php
/**
* @file
* Install, update and uninstall functions for the node_access_test_language
* module.
*/
/**
* Implements hook_install().
*
* Creates the 'private' field, which allows the node to be marked as private
* (restricted access) in a given translation.
*/
function node_access_test_language_install() {
$field_private = entity_create('field_entity', array(
'name' => 'field_private',
'entity_type' => 'node',
'type' => 'list_boolean',
'cardinality' => 1,
'translatable' => TRUE,
'settings' => array(
'allowed_values' => array(0 => 'Not private', 1 => 'Private'),
),
));
$field_private->save();
entity_create('field_instance', array(
'field_name' => $field_private->name,
'entity_type' => 'node',
'bundle' => 'page',
'widget' => array(
'type' => 'options_buttons',
),
))->save();
}
/**
* Implements hook_uninstall().
*/
function node_access_test_language_uninstall() {
field_read_instance('node', 'field_private', 'page')->delete();
}

View File

@ -42,39 +42,3 @@ function node_access_test_language_node_access_records(EntityInterface $node) {
} }
return $grants; return $grants;
} }
/**
* Implements hook_enable().
*
* Creates the 'private' field, which allows the node to be marked as private
* (restricted access) in a given translation.
*/
function node_access_test_language_enable() {
$field_private = entity_create('field_entity', array(
'name' => 'field_private',
'entity_type' => 'node',
'type' => 'list_boolean',
'cardinality' => 1,
'translatable' => TRUE,
'settings' => array(
'allowed_values' => array(0 => 'Not private', 1 => 'Private'),
),
));
$field_private->save();
entity_create('field_instance', array(
'field_name' => $field_private->name,
'entity_type' => 'node',
'bundle' => 'page',
'widget' => array(
'type' => 'options_buttons',
),
))->save();
}
/**
* Implements hook_disable().
*/
function node_access_test_language_disable() {
field_read_instance('node', 'field_private', 'page')->delete();
}

View File

@ -6,12 +6,12 @@
*/ */
/** /**
* Implements hook_enable(). * Implements hook_install().
* *
* If the module is being enabled through the admin UI, and not from an * If the module is being enabled through the admin UI, and not from an
* installation profile, reopen the modules page in an overlay. * installation profile, reopen the modules page in an overlay.
*/ */
function overlay_enable() { function overlay_install() {
if (strpos(current_path(), 'admin/modules') === 0) { if (strpos(current_path(), 'admin/modules') === 0) {
// Flag for a redirect to <front>#overlay=admin/modules on hook_init(). // Flag for a redirect to <front>#overlay=admin/modules on hook_init().
$_SESSION['overlay_enable_redirect'] = 1; $_SESSION['overlay_enable_redirect'] = 1;

View File

@ -50,7 +50,7 @@ class NodeTest extends RESTTestBase {
*/ */
public function testNodes() { public function testNodes() {
// Tests that the node resource works with comment module enabled. // Tests that the node resource works with comment module enabled.
$this->container->get('module_handler')->enable(array('comment')); $this->container->get('module_handler')->install(array('comment'));
$this->enableNodeConfiguration('GET', 'view'); $this->enableNodeConfiguration('GET', 'view');
$node = $this->entityCreate('node'); $node = $this->entityCreate('node');

View File

@ -162,9 +162,9 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
// away with a simple container holding the absolute bare minimum. When // away with a simple container holding the absolute bare minimum. When
// a kernel is overridden then there's no need to re-register the keyvalue // a kernel is overridden then there's no need to re-register the keyvalue
// service but when a test is happy with the superminimal container put // service but when a test is happy with the superminimal container put
// together here, it still might a keyvalue storage for anything (for // together here, it still might a keyvalue storage for anything using
// eg. module_enable) using \Drupal::state() -- that's why a memory // \Drupal::state() -- that's why a memory service was added in the first
// service was added in the first place. // place.
$container $container
->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory') ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory')
->addArgument(new Reference('service_container')); ->addArgument(new Reference('service_container'));

View File

@ -89,7 +89,7 @@ class DrupalUnitTestBaseTest extends DrupalUnitTestBase {
$this->assertFalse($schema, "'$table' table schema not found."); $this->assertFalse($schema, "'$table' table schema not found.");
// Install the module. // Install the module.
module_enable(array($module)); \Drupal::moduleHandler()->install(array($module));
// Verify that the enabled module exists. // Verify that the enabled module exists.
$this->assertTrue(module_exists($module), "$module module found."); $this->assertTrue(module_exists($module), "$module module found.");
@ -198,6 +198,9 @@ class DrupalUnitTestBaseTest extends DrupalUnitTestBase {
* Tests that the module list is retained after enabling/installing/disabling. * Tests that the module list is retained after enabling/installing/disabling.
*/ */
function testEnableModulesFixedList() { function testEnableModulesFixedList() {
// Install system module.
$this->container->get('module_handler')->install(array('system'));
// entity_test is loaded via $modules; its entity type should exist. // entity_test is loaded via $modules; its entity type should exist.
$this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE);
$this->assertTrue(TRUE == entity_get_info('entity_test')); $this->assertTrue(TRUE == entity_get_info('entity_test'));
@ -208,12 +211,12 @@ class DrupalUnitTestBaseTest extends DrupalUnitTestBase {
$this->assertTrue(TRUE == entity_get_info('entity_test')); $this->assertTrue(TRUE == entity_get_info('entity_test'));
// Install some other modules; entity_test should still exist. // Install some other modules; entity_test should still exist.
module_enable(array('field', 'field_sql_storage', 'field_test'), FALSE); $this->container->get('module_handler')->install(array('field', 'field_sql_storage', 'field_test'), FALSE);
$this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE);
$this->assertTrue(TRUE == entity_get_info('entity_test')); $this->assertTrue(TRUE == entity_get_info('entity_test'));
// Disable one of those modules; entity_test should still exist. // Uninstall one of those modules; entity_test should still exist.
module_disable(array('field_test')); $this->container->get('module_handler')->uninstall(array('field_test'));
$this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE);
$this->assertTrue(TRUE == entity_get_info('entity_test')); $this->assertTrue(TRUE == entity_get_info('entity_test'));
@ -222,7 +225,7 @@ class DrupalUnitTestBaseTest extends DrupalUnitTestBase {
$this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE);
$this->assertTrue(TRUE == entity_get_info('entity_test')); $this->assertTrue(TRUE == entity_get_info('entity_test'));
// Reactivate the disabled module without enabling it. // Reactivate the previously uninstalled module.
$this->enableModules(array('field_test')); $this->enableModules(array('field_test'));
// Create a field and an instance. // Create a field and an instance.

View File

@ -822,7 +822,7 @@ abstract class WebTestBase extends TestBase {
} }
if ($modules) { if ($modules) {
$modules = array_unique($modules); $modules = array_unique($modules);
$success = module_enable($modules, TRUE); $success = \Drupal::moduleHandler()->install($modules, TRUE);
$this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules)))); $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
$this->rebuildContainer(); $this->rebuildContainer();
} }

View File

@ -117,18 +117,11 @@ class ModulesListConfirmForm extends ConfirmFormBase implements ContainerInjecti
// were not manually selected. // were not manually selected.
foreach ($this->modules['dependencies'] as $module => $dependencies) { 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( $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], '@module' => $this->modules['install'][$module],
'@required' => implode(', ', $dependencies), '@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( $form['message'] = array(
'#theme' => 'item_list', '#theme' => 'item_list',
'#items' => $items, '#items' => $items,
@ -148,12 +141,9 @@ class ModulesListConfirmForm extends ConfirmFormBase implements ContainerInjecti
// Gets list of modules prior to install process. // Gets list of modules prior to install process.
$before = $this->moduleHandler->getModuleList(); $before = $this->moduleHandler->getModuleList();
// Installs, enables, and disables modules. // Install the given modules.
if (!empty($this->modules['enable'])) { if (!empty($this->modules['install'])) {
$this->moduleHandler->enable(array_keys($this->modules['enable'])); $this->moduleHandler->install(array_keys($this->modules['install']));
}
if (!empty($this->modules['disable'])) {
$this->moduleHandler->disable(array_keys($this->modules['disable']));
} }
// Gets module list after install process, flushes caches and displays a // Gets module list after install process, flushes caches and displays a

View File

@ -14,7 +14,7 @@ use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
* Provides module enable/disable interface. * Provides module installation interface.
* *
* The list of modules gets populated by module.info.yml files, which contain * The list of modules gets populated by module.info.yml files, which contain
* each module's name, description, and information about which modules it * each module's name, description, and information about which modules it
@ -117,7 +117,7 @@ class ModulesListForm extends FormBase {
'#title' => $this->t($package), '#title' => $this->t($package),
'#theme' => 'system_modules_details', '#theme' => 'system_modules_details',
'#header' => array( '#header' => array(
array('data' => '<span class="visually-hidden">' . $this->t('Enabled') . '</span>', 'class' => array('checkbox')), array('data' => '<span class="visually-hidden">' . $this->t('Installed') . '</span>', 'class' => array('checkbox')),
array('data' => $this->t('Name'), 'class' => array('name')), array('data' => $this->t('Name'), 'class' => array('name')),
array('data' => $this->t('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)), array('data' => $this->t('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)),
), ),
@ -206,8 +206,9 @@ class ModulesListForm extends FormBase {
// Present a checkbox for installing and indicating the status of a module. // Present a checkbox for installing and indicating the status of a module.
$row['enable'] = array( $row['enable'] = array(
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => $this->t('Enable'), '#title' => $this->t('Install'),
'#default_value' => (bool) $module->status, '#default_value' => (bool) $module->status,
'#disabled' => (bool) $module->status,
); );
// Disable the checkbox for required modules. // Disable the checkbox for required modules.
@ -301,67 +302,47 @@ class ModulesListForm extends FormBase {
} }
/** /**
* Helper function for building a list of modules to enable or disable. * Helper function for building a list of modules to install.
* *
* @param array $form_state * @param array $form_state
* The form state array. * The form state array.
* *
* @return array * @return array
* An array of modules to disable/enable and their dependencies. * An array of modules to install and their dependencies.
*/ */
protected function buildModuleList(array $form_state) { protected function buildModuleList(array $form_state) {
$packages = $form_state['values']['modules']; $packages = $form_state['values']['modules'];
// Build a list of modules to enable or disable. // Build a list of modules to install.
$modules = array( $modules = array(
'enable' => array(), 'install' => array(),
'disable' => array(),
'dependencies' => array(), 'dependencies' => array(),
'missing' => array(),
); );
// Build a list of missing dependencies. // Required modules have to be installed.
// @todo This should really not be handled here. // @todo This should really not be handled here.
$data = system_rebuild_module_data(); $data = system_rebuild_module_data();
foreach ($data as $name => $module) { foreach ($data as $name => $module) {
// Modules with missing dependencies have to be disabled. if (!empty($module->required) && !$this->moduleHandler->moduleExists($name)) {
if ($this->moduleHandler->moduleExists($name)) { $modules['install'][$name] = $module->info['name'];
foreach (array_keys($module->requires) as $dependency) {
if (!isset($data[$dependency])) {
$modules['missing'][$dependency][$name] = $module->info['name'];
$modules['disable'][$name] = $module->info['name'];
}
}
}
elseif (!empty($module->required)) {
$modules['enable'][$name] = $module->info['name'];
} }
} }
// First, build a list of all modules that were selected. // First, build a list of all modules that were selected.
foreach ($packages as $items) { foreach ($packages as $items) {
foreach ($items as $name => $checkbox) { foreach ($items as $name => $checkbox) {
// Do not override modules that are forced to be enabled/disabled. if ($checkbox['enable'] && !$this->moduleHandler->moduleExists($name)) {
if (isset($modules['enable'][$name]) || isset($modules['disable'][$name])) { $modules['install'][$name] = $data[$name]->info['name'];
continue;
}
$enabled = $this->moduleHandler->moduleExists($name);
if (!$checkbox['enable'] && $enabled) {
$modules['disable'][$name] = $data[$name]->info['name'];
}
elseif ($checkbox['enable'] && !$enabled) {
$modules['enable'][$name] = $data[$name]->info['name'];
} }
} }
} }
// Add all dependencies to a list. // Add all dependencies to a list.
while (list($module) = each($modules['enable'])) { while (list($module) = each($modules['install'])) {
foreach (array_keys($data[$module]->requires) as $dependency) { foreach (array_keys($data[$module]->requires) as $dependency) {
if (!isset($modules['enable'][$dependency]) && !$this->moduleHandler->moduleExists($dependency)) { if (!isset($modules['install'][$dependency]) && !$this->moduleHandler->moduleExists($dependency)) {
$modules['dependencies'][$module][$dependency] = $data[$dependency]->info['name']; $modules['dependencies'][$module][$dependency] = $data[$dependency]->info['name'];
$modules['enable'][$dependency] = $data[$dependency]->info['name']; $modules['install'][$dependency] = $data[$dependency]->info['name'];
} }
} }
} }
@ -371,11 +352,11 @@ class ModulesListForm extends FormBase {
// Invoke hook_requirements('install'). If failures are detected, make // Invoke hook_requirements('install'). If failures are detected, make
// sure the dependent modules aren't installed either. // sure the dependent modules aren't installed either.
foreach (array_keys($modules['enable']) as $module) { foreach (array_keys($modules['install']) as $module) {
if (drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED && !drupal_check_module($module)) { if (!drupal_check_module($module)) {
unset($modules['enable'][$module]); unset($modules['install'][$module]);
foreach (array_keys($data[$module]->required_by) as $dependent) { foreach (array_keys($data[$module]->required_by) as $dependent) {
unset($modules['enable'][$dependent]); unset($modules['install'][$dependent]);
unset($modules['dependencies'][$dependent]); unset($modules['dependencies'][$dependent]);
} }
} }
@ -388,11 +369,12 @@ class ModulesListForm extends FormBase {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function submitForm(array &$form, array &$form_state) { public function submitForm(array &$form, array &$form_state) {
// Retrieve a list of modules to enable/disable and their dependencies. // Retrieve a list of modules to install and their dependencies.
$modules = $this->buildModuleList($form_state); $modules = $this->buildModuleList($form_state);
// Check if we have to enable any dependencies. If there is one or more // Check if we have to install any dependencies. If there is one or more
// dependencies that are not enabled yet, redirect to the confirmation form. // dependencies that are not installed yet, redirect to the confirmation
// form.
if (!empty($modules['dependencies']) || !empty($modules['missing'])) { if (!empty($modules['dependencies']) || !empty($modules['missing'])) {
// Write the list of changed module states into a key value store. // Write the list of changed module states into a key value store.
$account = $this->currentUser()->id(); $account = $this->currentUser()->id();
@ -410,11 +392,8 @@ class ModulesListForm extends FormBase {
$before = $this->moduleHandler->getModuleList(); $before = $this->moduleHandler->getModuleList();
// There seem to be no dependencies that would need approval. // There seem to be no dependencies that would need approval.
if (!empty($modules['enable'])) { if (!empty($modules['install'])) {
$this->moduleHandler->enable(array_keys($modules['enable'])); $this->moduleHandler->install(array_keys($modules['install']));
}
if (!empty($modules['disable'])) {
$this->moduleHandler->disable(array_keys($modules['disable']));
} }
// Gets module list after install process, flushes caches and displays a // Gets module list after install process, flushes caches and displays a

View File

@ -70,15 +70,15 @@ class ModulesUninstallForm extends FormBase {
// Get a list of disabled, installed modules. // Get a list of disabled, installed modules.
$modules = system_rebuild_module_data(); $modules = system_rebuild_module_data();
$disabled = array_filter($modules, function ($module) { $uninstallable = array_filter($modules, function ($module) use ($modules) {
return empty($module->status) && drupal_get_installed_schema_version($module->name) > SCHEMA_UNINSTALLED; return empty($modules[$module->name]->info['required']) && drupal_get_installed_schema_version($module->name) > SCHEMA_UNINSTALLED;
}); });
$form['modules'] = array(); $form['modules'] = array();
// Only build the rest of the form if there are any modules available to // Only build the rest of the form if there are any modules available to
// uninstall; // uninstall;
if (empty($disabled)) { if (empty($uninstallable)) {
return $form; return $form;
} }
@ -86,10 +86,10 @@ class ModulesUninstallForm extends FormBase {
// Sort all modules by their name. // Sort all modules by their name.
$this->moduleHandler->loadInclude('system', 'inc', 'system.admin'); $this->moduleHandler->loadInclude('system', 'inc', 'system.admin');
uasort($disabled, 'system_sort_modules_by_info_name'); uasort($uninstallable, 'system_sort_modules_by_info_name');
$form['uninstall'] = array('#tree' => TRUE); $form['uninstall'] = array('#tree' => TRUE);
foreach ($disabled as $module) { foreach ($uninstallable as $module) {
$name = $module->info['name'] ?: $module->name; $name = $module->info['name'] ?: $module->name;
$form['modules'][$module->name]['#module_name'] = $name; $form['modules'][$module->name]['#module_name'] = $name;
$form['modules'][$module->name]['name']['#markup'] = $name; $form['modules'][$module->name]['name']['#markup'] = $name;
@ -107,7 +107,7 @@ class ModulesUninstallForm extends FormBase {
foreach (array_keys($module->required_by) as $dependent) { foreach (array_keys($module->required_by) as $dependent) {
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) { if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
$name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent; $name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent;
$form['modules'][$module->name]['#dependents'][] = $name; $form['modules'][$module->name]['#required_by'][] = $name;
$form['uninstall'][$module->name]['#disabled'] = TRUE; $form['uninstall'][$module->name]['#disabled'] = TRUE;
} }
} }

View File

@ -26,7 +26,7 @@ class EntityApiInfoTest extends WebTestBase {
* Ensures entity info cache is updated after changes. * Ensures entity info cache is updated after changes.
*/ */
function testEntityInfoChanges() { function testEntityInfoChanges() {
module_enable(array('entity_cache_test')); \Drupal::moduleHandler()->install(array('entity_cache_test'));
$entity_info = entity_get_info(); $entity_info = entity_get_info();
$this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.'); $this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.');
@ -39,8 +39,8 @@ class EntityApiInfoTest extends WebTestBase {
$info = entity_get_info('entity_cache_test'); $info = entity_get_info('entity_cache_test');
$this->assertEqual($info['label'], 'New label.', 'New label appears in entity info.'); $this->assertEqual($info['label'], 'New label.', 'New label appears in entity info.');
// Disable the providing module and make sure the entity type is gone. // Uninstall the providing module and make sure the entity type is gone.
module_disable(array('entity_cache_test', 'entity_cache_test_dependency')); module_uninstall(array('entity_cache_test', 'entity_cache_test_dependency'));
$entity_info = entity_get_info(); $entity_info = entity_get_info();
$this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.'); $this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.');
} }
@ -51,7 +51,7 @@ class EntityApiInfoTest extends WebTestBase {
* @see entity_cache_test_watchdog() * @see entity_cache_test_watchdog()
*/ */
function testEntityInfoCacheWatchdog() { function testEntityInfoCacheWatchdog() {
module_enable(array('entity_cache_test')); \Drupal::moduleHandler()->install(array('entity_cache_test'));
$info = \Drupal::state()->get('entity_cache_test'); $info = \Drupal::state()->get('entity_cache_test');
$this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.'); $this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.');
$this->assertEqual($info['controllers']['storage'], 'Drupal\Core\Entity\DatabaseStorageController', 'Entity controller class info is correct.'); $this->assertEqual($info['controllers']['storage'], 'Drupal\Core\Entity\DatabaseStorageController', 'Entity controller class info is correct.');

View File

@ -75,7 +75,7 @@ class LanguageSelectElementTest extends WebTestBase {
function testHiddenLanguageSelectElement() { function testHiddenLanguageSelectElement() {
// Disable the language module, so that the language select field will not // Disable the language module, so that the language select field will not
// be rendered. // be rendered.
module_disable(array('language')); module_uninstall(array('language'));
$this->drupalGet('form-test/language_select'); $this->drupalGet('form-test/language_select');
// Check that the language fields were rendered on the page. // Check that the language fields were rendered on the page.
$ids = array('edit-languages-all', 'edit-languages-configurable', 'edit-languages-locked', 'edit-languages-config-and-locked'); $ids = array('edit-languages-all', 'edit-languages-configurable', 'edit-languages-locked', 'edit-languages-config-and-locked');

View File

@ -622,7 +622,7 @@ class MenuRouterTest extends WebTestBase {
* Tests a menu on a router page. * Tests a menu on a router page.
*/ */
public function testMenuOnRoute() { public function testMenuOnRoute() {
module_enable(array('router_test')); \Drupal::moduleHandler()->install(array('router_test'));
\Drupal::service('router.builder')->rebuild(); \Drupal::service('router.builder')->rebuild();
$this->drupalGet('router_test/test2'); $this->drupalGet('router_test/test2');

View File

@ -34,7 +34,7 @@ class ClassLoaderTest extends WebTestBase {
*/ */
function testClassLoading() { function testClassLoading() {
// Enable the module_test and module_autoload_test modules. // Enable the module_test and module_autoload_test modules.
module_enable(array('module_test', 'module_autoload_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test', 'module_autoload_test'), FALSE);
$this->resetAll(); $this->resetAll();
// Check twice to test an unprimed and primed system_list() cache. // Check twice to test an unprimed and primed system_list() cache.
for ($i=0; $i<2; $i++) { for ($i=0; $i<2; $i++) {
@ -50,7 +50,7 @@ class ClassLoaderTest extends WebTestBase {
*/ */
function testClassLoadingDisabledModules() { function testClassLoadingDisabledModules() {
// Ensure that module_autoload_test is disabled. // Ensure that module_autoload_test is disabled.
module_disable(array('module_autoload_test'), FALSE); module_uninstall(array('module_autoload_test'), FALSE);
$this->resetAll(); $this->resetAll();
// Check twice to test an unprimed and primed system_list() cache. // Check twice to test an unprimed and primed system_list() cache.
for ($i=0; $i<2; $i++) { for ($i=0; $i<2; $i++) {

View File

@ -54,20 +54,6 @@ class DependencyTest extends ModuleTestBase {
$this->assertRaw(t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst('_missing_dependency'))), 'A module with missing dependencies is marked as such.'); $this->assertRaw(t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst('_missing_dependency'))), 'A module with missing dependencies is marked as such.');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_dependencies_test][enable]"]'); $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_dependencies_test][enable]"]');
$this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.'); $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
// Force enable the system_dependencies_test module.
module_enable(array('system_dependencies_test'), FALSE);
// Verify that the module is forced to be disabled when submitting
// the module page.
$this->drupalPostForm('admin/modules', array(), t('Save configuration'));
$this->assertText(t('The @module module is missing, so the following module will be disabled: @depends.', array('@module' => '_missing_dependency', '@depends' => 'System dependency test')), 'The module missing dependencies will be disabled.');
// Confirm.
$this->drupalPostForm(NULL, NULL, t('Continue'));
// Verify that the module has been disabled.
$this->assertModules(array('system_dependencies_test'), FALSE);
} }
/** /**
@ -103,7 +89,7 @@ class DependencyTest extends ModuleTestBase {
* Tests enabling a module that depends on a module which fails hook_requirements(). * Tests enabling a module that depends on a module which fails hook_requirements().
*/ */
function testEnableRequirementsFailureDependency() { function testEnableRequirementsFailureDependency() {
module_enable(array('comment')); \Drupal::moduleHandler()->install(array('comment'));
$this->assertModules(array('requirements1_test'), FALSE); $this->assertModules(array('requirements1_test'), FALSE);
$this->assertModules(array('requirements2_test'), FALSE); $this->assertModules(array('requirements2_test'), FALSE);
@ -130,7 +116,7 @@ class DependencyTest extends ModuleTestBase {
* UI. Dependencies should be enabled before their dependents. * UI. Dependencies should be enabled before their dependents.
*/ */
function testModuleEnableOrder() { function testModuleEnableOrder() {
module_enable(array('module_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test'), FALSE);
$this->resetAll(); $this->resetAll();
$this->assertModules(array('module_test'), TRUE); $this->assertModules(array('module_test'), TRUE);
\Drupal::state()->set('module_test.dependency', 'dependency'); \Drupal::state()->set('module_test.dependency', 'dependency');
@ -161,7 +147,7 @@ class DependencyTest extends ModuleTestBase {
$this->assertModules(array('forum', 'ban', 'xmlrpc', 'datetime', 'comment', 'history', 'taxonomy', 'options', 'number'), TRUE); $this->assertModules(array('forum', 'ban', 'xmlrpc', 'datetime', 'comment', 'history', 'taxonomy', 'options', 'number'), TRUE);
// Check the actual order which is saved by module_test_modules_enabled(). // Check the actual order which is saved by module_test_modules_enabled().
$module_order = \Drupal::state()->get('system_test.module_enable_order') ?: array(); $module_order = \Drupal::state()->get('module_test.install_order') ?: array();
$this->assertIdentical($module_order, $expected_order); $this->assertIdentical($module_order, $expected_order);
} }
@ -175,14 +161,6 @@ class DependencyTest extends ModuleTestBase {
$this->drupalPostForm(NULL, array(), t('Continue')); $this->drupalPostForm(NULL, array(), t('Continue'));
$this->assertModules(array('forum'), TRUE); $this->assertModules(array('forum'), TRUE);
// Disable forum and comment. Both should now be installed but disabled.
$edit = array('modules[Core][forum][enable]' => FALSE);
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
$edit = array('modules[Core][comment][enable]' => FALSE);
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('comment'), FALSE);
// Check that the taxonomy module cannot be uninstalled. // Check that the taxonomy module cannot be uninstalled.
$this->drupalGet('admin/modules/uninstall'); $this->drupalGet('admin/modules/uninstall');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]'); $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]');

View File

@ -1,226 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Module\EnableDisableTest.
*/
namespace Drupal\system\Tests\Module;
/**
* Tests functionality for enabling and disabling modules.
*/
class EnableDisableTest extends ModuleTestBase {
public static function getInfo() {
return array(
'name' => 'Enable/disable modules',
'description' => 'Enable/disable core module and confirm table creation/deletion.',
'group' => 'Module',
);
}
/**
* Tests that all core modules can be enabled, disabled and uninstalled.
*/
function testEnableDisable() {
$modules = system_rebuild_module_data();
foreach ($modules as $name => $module) {
// Filters all modules under core directory.
$in_core_path = (strpos($module->uri, 'core/modules') === 0);
// Filters test modules under Testing package.
$in_testing_package = ($module->info['package'] == 'Testing');
// Try to enable, disable and uninstall all core modules, unless they are
// hidden or required or system test modules.
if (!$in_core_path || !empty($module->info['hidden']) || !empty($module->info['required']) || $in_testing_package) {
unset($modules[$name]);
}
}
// Throughout this test, some modules may be automatically enabled (due to
// dependencies). We'll keep track of them in an array, so we can handle
// them separately.
$automatically_enabled = array();
// Remove already enabled modules (via installation profile).
// @todo Remove this after removing all dependencies from Testing profile.
foreach ($this->container->get('module_handler')->getModuleList() as $dependency => $filename) {
// Exclude required modules. Only installation profile "suggestions" can
// be disabled and uninstalled.
if (isset($modules[$dependency])) {
$automatically_enabled[$dependency] = TRUE;
}
}
$this->assertTrue(count($modules), format_string('Found @count modules that can be enabled: %modules', array(
'@count' => count($modules),
'%modules' => implode(', ', array_keys($modules)),
)));
// Enable the dblog module first, since we will be asserting the presence
// of log messages throughout the test.
if (isset($modules['dblog'])) {
$modules = array('dblog' => $modules['dblog']) + $modules;
}
// Set a variable so that the hook implementations in system_test.module
// will display messages via drupal_set_message().
\Drupal::state()->set('system_test.verbose_module_hooks', TRUE);
// Go through each module in the list and try to enable it (unless it was
// already enabled automatically due to a dependency).
foreach ($modules as $name => $module) {
if (empty($automatically_enabled[$name])) {
// Start a list of modules that we expect to be enabled this time.
$modules_to_enable = array($name);
// Find out if the module has any dependencies that aren't enabled yet;
// if so, add them to the list of modules we expect to be automatically
// enabled.
foreach (array_keys($module->requires) as $dependency) {
if (isset($modules[$dependency]) && empty($automatically_enabled[$dependency])) {
$modules_to_enable[] = $dependency;
$automatically_enabled[$dependency] = TRUE;
}
}
// Check that each module is not yet enabled and does not have any
// database tables yet.
foreach ($modules_to_enable as $module_to_enable) {
$this->assertModules(array($module_to_enable), FALSE);
$this->assertModuleTablesDoNotExist($module_to_enable);
}
// Install and enable the module.
$edit = array();
$package = $module->info['package'];
$edit['modules[' . $package . '][' . $name . '][enable]'] = $name;
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
// Handle the case where modules were installed along with this one and
// where we therefore hit a confirmation screen.
if (count($modules_to_enable) > 1) {
$this->drupalPostForm(NULL, array(), t('Continue'));
}
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
// Check that hook_modules_installed() and hook_modules_enabled() were
// invoked with the expected list of modules, that each module's
// database tables now exist, and that appropriate messages appear in
// the logs.
foreach ($modules_to_enable as $module_to_enable) {
$this->assertText(t('hook_modules_installed fired for @module', array('@module' => $module_to_enable)));
$this->assertText(t('hook_modules_enabled fired for @module', array('@module' => $module_to_enable)));
$this->assertModules(array($module_to_enable), TRUE);
$this->assertModuleTablesExist($module_to_enable);
$this->assertModuleConfig($module_to_enable);
$this->assertLogMessage('system', "%module module installed.", array('%module' => $module_to_enable), WATCHDOG_INFO);
$this->assertLogMessage('system', "%module module enabled.", array('%module' => $module_to_enable), WATCHDOG_INFO);
}
// Disable and uninstall the original module, and check appropriate
// hooks, tables, and log messages. (Later, we'll go back and do the
// same thing for modules that were enabled automatically.) Skip this
// for the dblog module, because that is needed for the test; we'll go
// back and do that one at the end also.
if ($name != 'dblog') {
$this->assertSuccessfulDisableAndUninstall($name, $package);
}
}
}
// Go through all modules that were automatically enabled, and try to
// disable and uninstall them one by one.
while (!empty($automatically_enabled)) {
$initial_count = count($automatically_enabled);
foreach (array_keys($automatically_enabled) as $name) {
$module = $modules[$name];
$package = $module->info['package'];
// If the module can't be disabled due to dependencies, skip it and try
// again the next time. Otherwise, try to disable it.
$this->drupalGet('admin/modules');
$disabled_checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[' . $package . '][' . $name . '][enable]"]');
if (empty($disabled_checkbox) && $name != 'dblog') {
unset($automatically_enabled[$name]);
$this->assertSuccessfulDisableAndUninstall($name, $package);
}
}
$final_count = count($automatically_enabled);
// If all checkboxes were disabled, something is really wrong with the
// test. Throw a failure and avoid an infinite loop.
if ($initial_count == $final_count) {
$this->fail(t('Remaining modules could not be disabled.'));
break;
}
}
// Disable and uninstall the dblog module last, since we needed it for
// assertions in all the above tests.
if (isset($modules['dblog'])) {
$this->assertSuccessfulDisableAndUninstall('dblog');
}
// Now that all modules have been tested, go back and try to enable them
// all again at once. This tests two things:
// - That each module can be successfully enabled again after being
// uninstalled.
// - That enabling more than one module at the same time does not lead to
// any errors.
$edit = array();
foreach ($modules as $name => $module) {
$edit['modules[' . $module->info['package'] . '][' . $name . '][enable]'] = $name;
}
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
}
/**
* Disables and uninstalls a module and asserts that it was done correctly.
*
* @param string $module
* The name of the module to disable and uninstall.
* @param string $package
* (optional) The package of the module to disable and uninstall. Defaults
* to 'Core'.
*/
function assertSuccessfulDisableAndUninstall($module, $package = 'Core') {
// Disable the module.
$edit = array();
$edit['modules[' . $package . '][' . $module . '][enable]'] = FALSE;
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
$this->assertModules(array($module), FALSE);
// Check that the appropriate hook was fired and the appropriate log
// message appears.
$this->assertText(t('hook_modules_disabled fired for @module', array('@module' => $module)));
if ($module != 'dblog') {
$this->assertLogMessage('system', "%module module disabled.", array('%module' => $module), WATCHDOG_INFO);
}
// Check that the module's database tables still exist.
$this->assertModuleTablesExist($module);
// Check that the module's config files still exist.
$this->assertModuleConfig($module);
// Uninstall the module.
$edit = array();
$edit['uninstall[' . $module . ']'] = $module;
$this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPostForm(NULL, NULL, t('Uninstall'));
$this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
$this->assertModules(array($module), FALSE);
// Check that the appropriate hook was fired and the appropriate log
// message appears. (But don't check for the log message if the dblog
// module was just uninstalled, since the {watchdog} table won't be there
// anymore.)
$this->assertText(t('hook_modules_uninstalled fired for @module', array('@module' => $module)));
if ($module != 'dblog') {
$this->assertLogMessage('system', "%module module uninstalled.", array('%module' => $module), WATCHDOG_INFO);
}
// Check that the module's database tables no longer exist.
$this->assertModuleTablesDoNotExist($module);
// Check that the module's config files no longer exist.
$this->assertNoModuleConfig($module);
}
}

View File

@ -7,6 +7,7 @@
namespace Drupal\system\Tests\Module; namespace Drupal\system\Tests\Module;
use Drupal\Core\Extension\ExtensionNameLengthException;
use Drupal\simpletest\WebTestBase; use Drupal\simpletest\WebTestBase;
/** /**
@ -41,11 +42,58 @@ class InstallTest extends WebTestBase {
* that modules are fully functional while Drupal is installing and enabling * that modules are fully functional while Drupal is installing and enabling
* them. * them.
*/ */
function testDrupalWriteRecord() { public function testDrupalWriteRecord() {
// Check for data that was inserted using drupal_write_record() while the // Check for data that was inserted using drupal_write_record() while the
// 'module_test' module was being installed and enabled. // 'module_test' module was being installed and enabled.
$data = db_query("SELECT data FROM {module_test}")->fetchCol(); $data = db_query("SELECT data FROM {module_test}")->fetchCol();
$this->assertTrue(in_array('Data inserted in hook_install()', $data), 'Data inserted using drupal_write_record() in hook_install() is correctly saved.'); $this->assertTrue(in_array('Data inserted in hook_install()', $data), 'Data inserted using drupal_write_record() in hook_install() is correctly saved.');
$this->assertTrue(in_array('Data inserted in hook_enable()', $data), 'Data inserted using drupal_write_record() in hook_enable() is correctly saved.'); }
/**
* Tests enabling User module once more.
*
* Regression: The installer might enable a module twice due to automatic
* dependency resolution. A bug caused the stored weight for User module to
* be an array.
*/
public function testEnableUserTwice() {
\Drupal::moduleHandler()->install(array('user'), FALSE);
$this->assertIdentical(config('system.module')->get('enabled.user'), '0');
}
/**
* Tests recorded schema versions of early installed modules in the installer.
*/
public function testRequiredModuleSchemaVersions() {
$version = drupal_get_installed_schema_version('system', TRUE);
$this->assertTrue($version > 0, 'System module version is > 0.');
$version = drupal_get_installed_schema_version('user', TRUE);
$this->assertTrue($version > 0, 'User module version is > 0.');
}
/**
* Tests that an exception is thrown when a module name is too long.
*/
public function testModuleNameLength() {
$module_name = 'invalid_module_name_over_the_maximum_allowed_character_length';
$message = format_string('Exception thrown when enabling module %name with a name length over the allowed maximum', array('%name' => $module_name));
try {
$this->container->get('module_handler')->install(array($module_name));
$this->fail($message);
}
catch (ExtensionNameLengthException $e) {
$this->pass($message);
}
// Since for the UI, the submit callback uses FALSE, test that too.
$message = format_string('Exception thrown when enabling as if via the UI the module %name with a name length over the allowed maximum', array('%name' => $module_name));
try {
$this->container->get('module_handler')->install(array($module_name), FALSE);
$this->fail($message);
}
catch (ExtensionNameLengthException $e) {
$this->pass($message);
} }
} }
}

View File

@ -0,0 +1,178 @@
<?php
/**
* @file
* Contains \Drupal\system\Tests\Module\InstallUninstallTest.
*/
namespace Drupal\system\Tests\Module;
/**
* Tests functionality for installing and uninstalling modules.
*/
class InstallUninstallTest extends ModuleTestBase {
public static $modules = array('system_test', 'dblog');
public static function getInfo() {
return array(
'name' => 'Install/uninstall modules',
'description' => 'Install/uninstall core module and confirm table creation/deletion.',
'group' => 'Module',
);
}
/**
* Tests that a fixed set of modules can be installed and uninstalled.
*/
public function testInstallUninstall() {
// Set a variable so that the hook implementations in system_test.module
// will display messages via drupal_set_message().
$this->container->get('state')->set('system_test.verbose_module_hooks', TRUE);
// Install and uninstall module_test to ensure hook_preinstall_module and
// hook_preuninstall_module are fired as expected.
$this->container->get('module_handler')->install(array('module_test'));
$this->assertEqual($this->container->get('state')->get('system_test_preinstall_module'), 'module_test');
$this->container->get('module_handler')->uninstall(array('module_test'));
$this->assertEqual($this->container->get('state')->get('system_test_preuninstall_module'), 'module_test');
// Try to install and uninstall book, toolbar modules and its dependencies.
$all_modules = system_rebuild_module_data();
$all_modules = array_filter($all_modules, function ($module) {
// Filter hidden, required and already enabled modules.
if (!empty($module->info['hidden']) || !empty($module->info['required']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
return FALSE;
}
return TRUE;
});
// Go through each module in the list and try to install it (unless it was
// already installed automatically due to a dependency).
$automatically_installed = array();
while (list($name, $module) = each($all_modules)) {
// Skip modules that have been automatically installed.
if (in_array($name, $automatically_installed)) {
continue;
}
// Start a list of modules that we expect to be installed this time.
$modules_to_install = array($name);
foreach (array_keys($module->requires) as $dependency) {
if (isset($all_modules[$dependency]) && !in_array($dependency, $automatically_installed)) {
$modules_to_install[] = $dependency;
// Add any potential dependency of this module to the list of modules we
// expect to be automatically installed.
$automatically_installed[] = $dependency;
}
}
// Check that each module is not yet enabled and does not have any
// database tables yet.
foreach ($modules_to_install as $module_to_install) {
$this->assertModules(array($module_to_install), FALSE);
$this->assertModuleTablesDoNotExist($module_to_install);
}
// Install the module.
$edit = array();
$package = $module->info['package'];
$edit["modules[$package][$name][enable]"] = TRUE;
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
// Handle the case where modules were installed along with this one and
// where we therefore hit a confirmation screen.
if (count($modules_to_install) > 1) {
$this->drupalPostForm(NULL, array(), t('Continue'));
}
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
// Check that hook_modules_installed() was invoked with the expected list
// of modules, that each module's database tables now exist, and that
// appropriate messages appear in the logs.
foreach ($modules_to_install as $module_to_install) {
$this->assertText(t('hook_modules_installed fired for @module', array('@module' => $module_to_install)));
$this->assertModules(array($module_to_install), TRUE);
$this->assertModuleTablesExist($module_to_install);
$this->assertModuleConfig($module_to_install);
$this->assertLogMessage('system', "%module module installed.", array('%module' => $module_to_install), WATCHDOG_INFO);
}
// Uninstall the original module, and check appropriate
// hooks, tables, and log messages. (Later, we'll go back and do the
// same thing for modules that were enabled automatically.)
$this->assertSuccessfullUninstall($name, $package);
}
// Go through all modules that were automatically installed, and try to
// uninstall them one by one.
while ($automatically_installed) {
$initial_count = count($automatically_installed);
foreach ($automatically_installed as $name) {
$package = $all_modules[$name]->info['package'];
// If the module can't be uninstalled due to dependencies, skip it and
// try again the next time. Otherwise, try to uninstall it.
$this->drupalGet('admin/modules/uninstall');
$disabled_checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[' . $name . ']"]');
if (empty($disabled_checkbox)) {
$automatically_installed = array_diff($automatically_installed, array($name));
$this->assertSuccessfullUninstall($name, $package);
}
}
$final_count = count($automatically_installed);
// If all checkboxes were disabled, something is really wrong with the
// test. Throw a failure and avoid an infinite loop.
if ($initial_count == $final_count) {
$this->fail('Remaining modules could not be disabled.');
break;
}
}
// Now that all modules have been tested, go back and try to enable them
// all again at once. This tests two things:
// - That each module can be successfully enabled again after being
// uninstalled.
// - That enabling more than one module at the same time does not lead to
// any errors.
$edit = array();
foreach ($all_modules as $name => $module) {
$edit['modules[' . $module->info['package'] . '][' . $name . '][enable]'] = TRUE;
}
$this->drupalPostForm('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
}
/**
* Uninstalls a module and asserts that it was done correctly.
*
* @param string $module
* The name of the module to uninstall.
* @param string $package
* (optional) The package of the module to uninstall. Defaults
* to 'Core'.
*/
protected function assertSuccessfullUninstall($module, $package = 'Core') {
$edit = array();
$edit['uninstall[' . $module . ']'] = TRUE;
$this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPostForm(NULL, NULL, t('Uninstall'));
$this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
$this->assertModules(array($module), FALSE);
// Check that the appropriate hook was fired and the appropriate log
// message appears. (But don't check for the log message if the dblog
// module was just uninstalled, since the {watchdog} table won't be there
// anymore.)
$this->assertText(t('hook_modules_uninstalled fired for @module', array('@module' => $module)));
$this->assertLogMessage('system', "%module module uninstalled.", array('%module' => $module), WATCHDOG_INFO);
// Check that the module's database tables no longer exist.
$this->assertModuleTablesDoNotExist($module);
// Check that the module's config files no longer exist.
$this->assertNoModuleConfig($module);
}
}

View File

@ -43,7 +43,7 @@ class ModuleApiTest extends WebTestBase {
$this->assertModuleList($module_list, t('Standard profile')); $this->assertModuleList($module_list, t('Standard profile'));
// Try to install a new module. // Try to install a new module.
module_enable(array('ban')); \Drupal::moduleHandler()->install(array('ban'));
$module_list[] = 'ban'; $module_list[] = 'ban';
sort($module_list); sort($module_list);
$this->assertModuleList($module_list, t('After adding a module')); $this->assertModuleList($module_list, t('After adding a module'));
@ -98,18 +98,18 @@ class ModuleApiTest extends WebTestBase {
$this->assertTrue(cache('bootstrap')->get('module_implements'), 'The module implements cache is populated after requesting a page.'); $this->assertTrue(cache('bootstrap')->get('module_implements'), 'The module implements cache is populated after requesting a page.');
// Prime ModuleHandler's hook implementation cache by invoking a random hook // Prime ModuleHandler's hook implementation cache by invoking a random hook
// name. The subsequent module_enable() below will only call into // name. The subsequent \Drupal\Core\Extension\ModuleHandler::install()
// setModuleList(), but will not explicitly reset the hook implementation // below will only call into setModuleList(), but will not explicitly reset
// cache, as that is expected to happen implicitly by setting the module // the hook implementation cache, as that is expected to happen implicitly
// list. This verifies that the hook implementation cache is cleared // by setting the module list. This verifies that the hook implementation
// whenever setModuleList() is called. // cache is cleared whenever setModuleList() is called.
$module_handler = \Drupal::moduleHandler(); $module_handler = \Drupal::moduleHandler();
$module_handler->invokeAll('test'); $module_handler->invokeAll('test');
// Make sure group include files are detected properly even when the file is // Make sure group include files are detected properly even when the file is
// already loaded when the cache is rebuilt. // already loaded when the cache is rebuilt.
// For that activate the module_test which provides the file to load. // For that activate the module_test which provides the file to load.
module_enable(array('module_test')); \Drupal::moduleHandler()->install(array('module_test'));
$module_handler->loadAll(); $module_handler->loadAll();
module_load_include('inc', 'module_test', 'module_test.file'); module_load_include('inc', 'module_test', 'module_test.file');
$modules = $module_handler->getImplementations('test_hook'); $modules = $module_handler->getImplementations('test_hook');
@ -120,7 +120,7 @@ class ModuleApiTest extends WebTestBase {
* Test that module_invoke() can load a hook defined in hook_hook_info(). * Test that module_invoke() can load a hook defined in hook_hook_info().
*/ */
function testModuleInvoke() { function testModuleInvoke() {
module_enable(array('module_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test'), FALSE);
$this->resetAll(); $this->resetAll();
$this->drupalGet('module-test/hook-dynamic-loading-invoke'); $this->drupalGet('module-test/hook-dynamic-loading-invoke');
$this->assertText('success!', 'module_invoke() dynamically loads a hook defined in hook_hook_info().'); $this->assertText('success!', 'module_invoke() dynamically loads a hook defined in hook_hook_info().');
@ -130,7 +130,7 @@ class ModuleApiTest extends WebTestBase {
* Test that module_invoke_all() can load a hook defined in hook_hook_info(). * Test that module_invoke_all() can load a hook defined in hook_hook_info().
*/ */
function testModuleInvokeAll() { function testModuleInvokeAll() {
module_enable(array('module_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test'), FALSE);
$this->resetAll(); $this->resetAll();
$this->drupalGet('module-test/hook-dynamic-loading-invoke-all'); $this->drupalGet('module-test/hook-dynamic-loading-invoke-all');
$this->assertText('success!', 'module_invoke_all() dynamically loads a hook defined in hook_hook_info().'); $this->assertText('success!', 'module_invoke_all() dynamically loads a hook defined in hook_hook_info().');
@ -143,7 +143,7 @@ class ModuleApiTest extends WebTestBase {
* functions execute early in the request handling. * functions execute early in the request handling.
*/ */
function testModuleInvokeAllDuringLoadFunction() { function testModuleInvokeAllDuringLoadFunction() {
module_enable(array('module_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test'), FALSE);
$this->resetAll(); $this->resetAll();
$this->drupalGet('module-test/hook-dynamic-loading-invoke-all-during-load/module_test'); $this->drupalGet('module-test/hook-dynamic-loading-invoke-all-during-load/module_test');
$this->assertText('success!', 'Menu item load function invokes a hook defined in hook_hook_info().'); $this->assertText('success!', 'Menu item load function invokes a hook defined in hook_hook_info().');
@ -156,7 +156,7 @@ class ModuleApiTest extends WebTestBase {
// Enable the test module, and make sure that other modules we are testing // Enable the test module, and make sure that other modules we are testing
// are not already enabled. (If they were, the tests below would not work // are not already enabled. (If they were, the tests below would not work
// correctly.) // correctly.)
module_enable(array('module_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test'), FALSE);
$this->assertTrue(module_exists('module_test'), 'Test module is enabled.'); $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
$this->assertFalse(module_exists('forum'), 'Forum module is disabled.'); $this->assertFalse(module_exists('forum'), 'Forum module is disabled.');
$this->assertFalse(module_exists('ban'), 'Ban module is disabled.'); $this->assertFalse(module_exists('ban'), 'Ban module is disabled.');
@ -166,53 +166,24 @@ class ModuleApiTest extends WebTestBase {
// depends on a made-up module, foo. Nothing should be installed. // depends on a made-up module, foo. Nothing should be installed.
\Drupal::state()->set('module_test.dependency', 'missing dependency'); \Drupal::state()->set('module_test.dependency', 'missing dependency');
drupal_static_reset('system_rebuild_module_data'); drupal_static_reset('system_rebuild_module_data');
$result = module_enable(array('forum')); $result = \Drupal::moduleHandler()->install(array('forum'));
$this->assertFalse($result, 'module_enable() returns FALSE if dependencies are missing.'); $this->assertFalse($result, '\Drupal\Core\Extension\ModuleHandler::install() returns FALSE if dependencies are missing.');
$this->assertFalse(module_exists('forum'), 'module_enable() aborts if dependencies are missing.'); $this->assertFalse(module_exists('forum'), '\Drupal\Core\Extension\ModuleHandler::install() aborts if dependencies are missing.');
// Now, fix the missing dependency. Forum module depends on ban, but ban // Now, fix the missing dependency. Forum module depends on ban, but ban
// depends on the XML-RPC module. module_enable() should work. // depends on the XML-RPC module.
// \Drupal\Core\Extension\ModuleHandler::install() should work.
\Drupal::state()->set('module_test.dependency', 'dependency'); \Drupal::state()->set('module_test.dependency', 'dependency');
drupal_static_reset('system_rebuild_module_data'); drupal_static_reset('system_rebuild_module_data');
$result = module_enable(array('forum')); $result = \Drupal::moduleHandler()->install(array('forum'));
$this->assertTrue($result, 'module_enable() returns the correct value.'); $this->assertTrue($result, '\Drupal\Core\Extension\ModuleHandler::install() returns the correct value.');
// Verify that the fake dependency chain was installed. // Verify that the fake dependency chain was installed.
$this->assertTrue(module_exists('ban') && module_exists('xmlrpc'), 'Dependency chain was installed by module_enable().'); $this->assertTrue(module_exists('ban') && module_exists('xmlrpc'), 'Dependency chain was installed.');
// Verify that the original module was installed. // Verify that the original module was installed.
$this->assertTrue(module_exists('forum'), 'Module installation with unlisted dependencies succeeded.'); $this->assertTrue(module_exists('forum'), 'Module installation with unlisted dependencies succeeded.');
// Finally, verify that the modules were enabled in the correct order. // Finally, verify that the modules were enabled in the correct order.
$module_order = \Drupal::state()->get('system_test.module_enable_order') ?: array(); $module_order = \Drupal::state()->get('module_test.install_order') ?: array();
$this->assertEqual($module_order, array('xmlrpc', 'ban', 'forum'), 'Modules were enabled in the correct order by module_enable().'); $this->assertEqual($module_order, array('xmlrpc', 'ban', 'forum'), 'Modules were enabled in the correct order.');
// Now, disable the XML-RPC module. Both forum and ban should be disabled as
// well, in the correct order.
module_disable(array('xmlrpc'));
$this->assertTrue(!module_exists('forum') && !module_exists('ban'), 'Depedency chain was disabled by module_disable().');
$this->assertFalse(module_exists('xmlrpc'), 'Disabling a module with unlisted dependents succeeded.');
$disabled_modules = \Drupal::state()->get('module_test.disable_order') ?: array();
$this->assertEqual($disabled_modules, array('forum', 'ban', 'xmlrpc'), 'Modules were disabled in the correct order by module_disable().');
// Disable a module that is listed as a dependency by the installation
// profile. Make sure that the profile itself is not on the list of
// dependent modules to be disabled.
$profile = drupal_get_profile();
$info = install_profile_info($profile);
$this->assertTrue(in_array('comment', $info['dependencies']), 'Comment module is listed as a dependency of the installation profile.');
$this->assertTrue(module_exists('comment'), 'Comment module is enabled.');
module_disable(array('comment'));
$this->assertFalse(module_exists('comment'), 'Comment module was disabled.');
$disabled_modules = \Drupal::state()->get('module_test.disable_order') ?: array();
$this->assertTrue(in_array('comment', $disabled_modules), 'Comment module is in the list of disabled modules.');
$this->assertFalse(in_array($profile, $disabled_modules), 'The installation profile is not in the list of disabled modules.');
// Try to uninstall the XML-RPC module by itself. This should be rejected,
// since the modules which it depends on need to be uninstalled first, and
// that is too destructive to perform automatically.
$result = module_uninstall(array('xmlrpc'));
$this->assertFalse($result, 'Calling module_uninstall() on a module whose dependents are not uninstalled fails.');
foreach (array('forum', 'ban', 'xmlrpc') as $module) {
$this->assertNotEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was not uninstalled.', array('@module' => $module)));
}
// Now uninstall all three modules explicitly, but in the incorrect order, // Now uninstall all three modules explicitly, but in the incorrect order,
// and make sure that drupal_uninstal_modules() uninstalled them in the // and make sure that drupal_uninstal_modules() uninstalled them in the
@ -232,28 +203,28 @@ class ModuleApiTest extends WebTestBase {
$this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, 'Comment module was uninstalled.'); $this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, 'Comment module was uninstalled.');
$uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order') ?: array(); $uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order') ?: array();
$this->assertTrue(in_array('comment', $uninstalled_modules), 'Comment module is in the list of uninstalled modules.'); $this->assertTrue(in_array('comment', $uninstalled_modules), 'Comment module is in the list of uninstalled modules.');
$this->assertFalse(in_array($profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.'); $this->assertFalse(in_array($this->profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.');
// Enable forum module again, which should enable both the ban module and // Enable forum module again, which should enable both the ban module and
// XML-RPC module. But, this time do it with ban module declaring a // XML-RPC module. But, this time do it with ban module declaring a
// dependency on a specific version of XML-RPC module in its info file. Make // dependency on a specific version of XML-RPC module in its info file. Make
// sure that module_enable() still works. // sure that Drupal\Core\Extension\ModuleHandler::install() still works.
\Drupal::state()->set('module_test.dependency', 'version dependency'); \Drupal::state()->set('module_test.dependency', 'version dependency');
drupal_static_reset('system_rebuild_module_data'); drupal_static_reset('system_rebuild_module_data');
$result = module_enable(array('forum')); $result = \Drupal::moduleHandler()->install(array('forum'));
$this->assertTrue($result, 'module_enable() returns the correct value.'); $this->assertTrue($result, '\Drupal\Core\Extension\ModuleHandler::install() returns the correct value.');
// Verify that the fake dependency chain was installed. // Verify that the fake dependency chain was installed.
$this->assertTrue(module_exists('ban') && module_exists('xmlrpc'), 'Dependency chain was installed by module_enable().'); $this->assertTrue(module_exists('ban') && module_exists('xmlrpc'), 'Dependency chain was installed.');
// Verify that the original module was installed. // Verify that the original module was installed.
$this->assertTrue(module_exists('forum'), 'Module installation with version dependencies succeeded.'); $this->assertTrue(module_exists('forum'), 'Module installation with version dependencies succeeded.');
// Finally, verify that the modules were enabled in the correct order. // Finally, verify that the modules were enabled in the correct order.
$enable_order = \Drupal::state()->get('system_test.module_enable_order') ?: array(); $enable_order = \Drupal::state()->get('module_test.install_order') ?: array();
$xmlrpc_position = array_search('xmlrpc', $enable_order); $xmlrpc_position = array_search('xmlrpc', $enable_order);
$ban_position = array_search('ban', $enable_order); $ban_position = array_search('ban', $enable_order);
$forum_position = array_search('forum', $enable_order); $forum_position = array_search('forum', $enable_order);
$xmlrpc_before_ban = $xmlrpc_position !== FALSE && $ban_position !== FALSE && $xmlrpc_position < $ban_position; $xmlrpc_before_ban = $xmlrpc_position !== FALSE && $ban_position !== FALSE && $xmlrpc_position < $ban_position;
$ban_before_forum = $ban_position !== FALSE && $forum_position !== FALSE && $ban_position < $forum_position; $ban_before_forum = $ban_position !== FALSE && $forum_position !== FALSE && $ban_position < $forum_position;
$this->assertTrue($xmlrpc_before_ban && $ban_before_forum, 'Modules were enabled in the correct order by module_enable().'); $this->assertTrue($xmlrpc_before_ban && $ban_before_forum, 'Modules were enabled in the correct order.');
} }
/** /**

View File

@ -1,73 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\system\Tests\Module\ModuleEnableTest.
*/
namespace Drupal\system\Tests\Module;
use Drupal\Core\Extension\ExtensionNameLengthException;
use Drupal\simpletest\WebTestBase;
/**
* Tests enabling modules.
*/
class ModuleEnableTest extends WebTestBase {
public static function getInfo() {
return array(
'name' => 'Module enable',
'description' => 'Tests enabling modules.',
'group' => 'Module',
);
}
/**
* Tests enabling User module once more.
*
* Regression: The installer might enable a module twice due to automatic
* dependency resolution. A bug caused the stored weight for User module to
* be an array.
*/
function testEnableUserTwice() {
$this->container->get('module_handler')->enable(array('user'), FALSE);
$this->assertIdentical(\Drupal::config('system.module')->get('enabled.user'), '0');
}
/**
* Tests recorded schema versions of early installed modules in the installer.
*/
function testRequiredModuleSchemaVersions() {
$version = drupal_get_installed_schema_version('system', TRUE);
$this->assertTrue($version > 0, 'System module version is > 0.');
$version = drupal_get_installed_schema_version('user', TRUE);
$this->assertTrue($version > 0, 'User module version is > 0.');
}
/**
* Tests that an exception is thrown when a module name is too long.
*/
function testModuleNameLength() {
$module_name = 'invalid_module_name_over_the_maximum_allowed_character_length';
$message = format_string('Exception thrown when enabling module %name with a name length over the allowed maximum', array('%name' => $module_name));
try {
$this->container->get('module_handler')->enable(array($module_name));
$this->fail($message);
}
catch (ExtensionNameLengthException $e) {
$this->pass($message);
}
// Since for the UI, the submit callback uses FALSE, test that too.
$message = format_string('Exception thrown when enabling as if via the UI the module %name with a name length over the allowed maximum', array('%name' => $module_name));
try {
$this->container->get('module_handler')->enable(array($module_name), FALSE);
$this->fail($message);
}
catch (ExtensionNameLengthException $e) {
$this->pass($message);
}
}
}

View File

@ -35,7 +35,6 @@ class UninstallTest extends WebTestBase {
function testUserPermsUninstalled() { function testUserPermsUninstalled() {
// Uninstalls the module_test module, so hook_modules_uninstalled() // Uninstalls the module_test module, so hook_modules_uninstalled()
// is executed. // is executed.
module_disable(array('module_test'));
module_uninstall(array('module_test')); module_uninstall(array('module_test'));
// Are the perms defined by module_test removed? // Are the perms defined by module_test removed?

View File

@ -12,13 +12,6 @@ namespace Drupal\system\Tests\Module;
*/ */
class VersionTest extends ModuleTestBase { class VersionTest extends ModuleTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('module_test');
public static function getInfo() { public static function getInfo() {
return array( return array(
'name' => 'Module versions', 'name' => 'Module versions',

View File

@ -46,12 +46,12 @@ class ServiceProviderTest extends WebTestBase {
* Tests that the DIC keeps up with module enable/disable in the same request. * Tests that the DIC keeps up with module enable/disable in the same request.
*/ */
function testServiceProviderRegistrationDynamic() { function testServiceProviderRegistrationDynamic() {
// Disable the module and ensure the service provider's service is not registered. // Uninstall the module and ensure the service provider's service is not registered.
module_disable(array('service_provider_test')); \Drupal::moduleHandler()->uninstall(array('service_provider_test'));
$this->assertFalse(drupal_container()->has('service_provider_test_class'), 'The service_provider_test_class service does not exist in the DIC.'); $this->assertFalse(drupal_container()->has('service_provider_test_class'), 'The service_provider_test_class service does not exist in the DIC.');
// Enable the module and ensure the service provider's service is registered. // Install the module and ensure the service provider's service is registered.
module_enable(array('service_provider_test')); \Drupal::moduleHandler()->install(array('service_provider_test'));
$this->assertTrue(drupal_container()->has('service_provider_test_class'), 'The service_provider_test_class service exists in the DIC.'); $this->assertTrue(drupal_container()->has('service_provider_test_class'), 'The service_provider_test_class service exists in the DIC.');
} }

View File

@ -42,7 +42,7 @@ class DefaultMobileMetaTagsTest extends WebTestBase {
* Verifies that the default mobile meta tags can be removed. * Verifies that the default mobile meta tags can be removed.
*/ */
public function testRemovingDefaultMetaTags() { public function testRemovingDefaultMetaTags() {
module_enable(array('system_module_test')); \Drupal::moduleHandler()->install(array('system_module_test'));
$this->drupalGet(''); $this->drupalGet('');
foreach ($this->default_metatags as $name => $metatag) { foreach ($this->default_metatags as $name => $metatag) {
$this->assertNoRaw($metatag, String::format('Default Mobile meta tag "@name" removed properly.', array('@name' => $name)), 'System'); $this->assertNoRaw($metatag, String::format('Default Mobile meta tag "@name" removed properly.', array('@name' => $name)), 'System');

View File

@ -31,7 +31,7 @@ class InfoAlterTest extends WebTestBase {
function testSystemInfoAlter() { function testSystemInfoAlter() {
// Enable seven and the test module. // Enable seven and the test module.
theme_enable(array('seven')); theme_enable(array('seven'));
module_enable(array('module_test'), FALSE); \Drupal::moduleHandler()->install(array('module_test'), FALSE);
$this->assertTrue(module_exists('module_test'), 'Test module is enabled.'); $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
// Verify that the rebuilt and altered theme info is returned. // Verify that the rebuilt and altered theme info is returned.
@ -44,19 +44,5 @@ class InfoAlterTest extends WebTestBase {
$this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was returned by system_list().'); $this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was returned by system_list().');
$list_themes = list_themes(); $list_themes = list_themes();
$this->assertTrue(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was returned by list_themes().'); $this->assertTrue(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was returned by list_themes().');
// Disable the module and verify that rebuilt .info.yml does not contain it.
module_disable(array('module_test'), FALSE);
$this->assertFalse(module_exists('module_test'), 'Test module is disabled.');
$info = system_get_info('theme', 'seven');
$this->assertFalse(isset($info['regions']['test_region']), 'Altered theme info was not returned by system_get_info().');
$seven_regions = system_region_list('seven');
$this->assertFalse(isset($seven_regions['test_region']), 'Altered theme info was not returned by system_region_list().');
$system_list_themes = system_list('theme');
$info = $system_list_themes['seven']->info;
$this->assertFalse(isset($info['regions']['test_region']), 'Altered theme info was not returned by system_list().');
$list_themes = list_themes();
$this->assertFalse(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was not returned by list_themes().');
} }
} }

View File

@ -52,12 +52,13 @@ class MainContentFallbackTest extends WebTestBase {
*/ */
function testMainContentFallback() { function testMainContentFallback() {
$edit = array(); $edit = array();
// Disable the block module. // Uninstall the block module.
$edit['modules[Core][block][enable]'] = FALSE; $edit['uninstall[block]'] = 'block';
$this->drupalPostForm('admin/modules', $edit, t('Save configuration')); $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); $this->drupalPostForm(NULL, NULL, t('Uninstall'));
$this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
$this->rebuildContainer(); $this->rebuildContainer();
$this->assertFalse(module_exists('block'), 'Block module disabled.'); $this->assertFalse(module_exists('block'), 'Block module uninstall.');
// At this point, no region is filled and fallback should be triggered. // At this point, no region is filled and fallback should be triggered.
$this->drupalGet('admin/config/system/site-information'); $this->drupalGet('admin/config/system/site-information');

View File

@ -254,7 +254,7 @@ class ThemeTest extends WebTestBase {
* Test that themes can't be enabled when the base theme or engine is missing. * Test that themes can't be enabled when the base theme or engine is missing.
*/ */
function testInvalidTheme() { function testInvalidTheme() {
module_enable(array('theme_page_test')); \Drupal::moduleHandler()->install(array('theme_page_test'));
$this->drupalGet('admin/appearance'); $this->drupalGet('admin/appearance');
$this->assertText(t('This theme requires the base theme @base_theme to operate correctly.', array('@base_theme' => 'not_real_test_basetheme')), 'Invalid base theme check succeeded.'); $this->assertText(t('This theme requires the base theme @base_theme to operate correctly.', array('@base_theme' => 'not_real_test_basetheme')), 'Invalid base theme check succeeded.');
$this->assertText(t('This theme requires the theme engine @theme_engine to operate correctly.', array('@theme_engine' => 'not_real_engine')), 'Invalid theme engine check succeeded.'); $this->assertText(t('This theme requires the theme engine @theme_engine to operate correctly.', array('@theme_engine' => 'not_real_engine')), 'Invalid theme engine check succeeded.');

View File

@ -218,29 +218,6 @@ class ThemeTest extends WebTestBase {
$this->assertIdentical(theme_get_setting('basetheme_only', 'test_subtheme'), 'base theme value', 'Base theme\'s default settings values are inherited by subtheme.'); $this->assertIdentical(theme_get_setting('basetheme_only', 'test_subtheme'), 'base theme value', 'Base theme\'s default settings values are inherited by subtheme.');
} }
/**
* Ensures the theme registry is rebuilt when modules are disabled/enabled.
*/
function testRegistryRebuild() {
$this->assertThemeOutput('theme_test_foo', array('foo' => 'a'), 'a', 'The theme registry contains theme_test_foo.');
module_disable(array('theme_test'), FALSE);
// After enabling/disabling a module during a test, we need to rebuild the
// container and ensure the extension handler is loaded, otherwise theme()
// throws an exception.
$this->rebuildContainer();
$this->container->get('module_handler')->loadAll();
$this->assertThemeOutput('theme_test_foo', array('foo' => 'b'), FALSE, 'The theme registry does not contain theme_test_foo, because the module is disabled.');
module_enable(array('theme_test'), FALSE);
// After enabling/disabling a module during a test, we need to rebuild the
// container and ensure the extension handler is loaded, otherwise theme()
// throws an exception.
$this->rebuildContainer();
$this->container->get('module_handler')->loadAll();
$this->assertThemeOutput('theme_test_foo', array('foo' => 'c'), 'c', 'The theme registry contains theme_test_foo again after re-enabling the module.');
}
/** /**
* Tests child element rendering for 'render element' theme hooks. * Tests child element rendering for 'render element' theme hooks.
*/ */

View File

@ -34,25 +34,21 @@ class ModulesDisabledUpgradePathTest extends UpgradePathTestBase {
* Tests an upgrade with all non-required modules installed but disabled. * Tests an upgrade with all non-required modules installed but disabled.
*/ */
public function testDisabledUpgrade() { public function testDisabledUpgrade() {
$this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $modules = db_query('SELECT name, info FROM {system} WHERE type = :module AND status = 0 AND schema_version <> :schema_uninstalled', array(
':module' => 'module',
// Get enabled modules. ':schema_uninstalled' => SCHEMA_UNINSTALLED,
$enabled = \Drupal::moduleHandler()->getModuleList(); ))->fetchAllKeyed(0, 1);
// Get all available modules. array_walk($modules, function (&$value, $key) {
$available = system_rebuild_module_data(); $info = unserialize($value);
// Filter out hidden test modules. $value = $info['name'];
foreach ($available as $module => $data) { });
if (!empty($data->info['hidden'])) { // Load the first update screen.
unset($available[$module]); $this->getUpdatePhp();
} if (!$this->assertResponse(200)) {
} throw new \Exception('Initial GET to update.php did not return HTTP 200 status.');
$to_enable = array_diff_key($available, $enabled); }
module_enable(array_keys($to_enable)); $this->assertNoFieldByXPath('//input[@type="submit"]', NULL, 'No continue button found on update.php.');
// Check for updates. $this->assertText('Drupal 8 no longer supports disabled modules. Please either enable or uninstall them before upgrading.');
require_once DRUPAL_ROOT . '/core/includes/update.inc'; $this->assertText(implode(', ', $modules));
require_once DRUPAL_ROOT . '/core/includes/install.inc';
$updates = update_get_update_list();
$this->assertEqual($updates, array(), 'No pending updates after enabling all modules.');
$this->assertTrue(\Drupal::state()->get('update_test_1_update_dependencies_run'), 'Module update dependencies resolved for disabled modules');
} }
} }

View File

@ -619,11 +619,11 @@ function theme_system_modules_uninstall($variables) {
// Display table. // Display table.
$rows = array(); $rows = array();
foreach (element_children($form['modules']) as $module) { foreach (element_children($form['modules']) as $module) {
if (!empty($form['modules'][$module]['#dependents'])) { if (!empty($form['modules'][$module]['#required_by'])) {
$disabled_message = format_plural(count($form['modules'][$module]['#dependents']), $disabled_message = format_plural(count($form['modules'][$module]['#required_by']),
'To uninstall @module, the following module must be uninstalled first: @required_modules', 'To uninstall @module, the following module must be uninstalled first: @required_modules',
'To uninstall @module, the following modules 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]['#dependents']))); array('@module' => $form['modules'][$module]['#module_name'], '@required_modules' => implode(', ', $form['modules'][$module]['#required_by'])));
$disabled_message = '<div class="admin-requirements">' . $disabled_message . '</div>'; $disabled_message = '<div class="admin-requirements">' . $disabled_message . '</div>';
} }
else { else {

View File

@ -1929,26 +1929,12 @@ function hook_rebuild() {
} }
/** /**
* Perform necessary actions before modules are installed. * Perform necessary actions before a module is installed.
* *
* This function allows all modules to react prior to a module being installed. * @param string $module
* * The name of the module about to be installed.
* @param $modules
* An array of modules about to be installed.
*/ */
function hook_modules_preinstall($modules) { function hook_module_preinstall($module) {
mymodule_cache_clear();
}
/**
* Perform necessary actions before modules are enabled.
*
* This function allows all modules to react prior to a module being enabled.
*
* @param $module
* An array of modules about to be enabled.
*/
function hook_modules_preenable($modules) {
mymodule_cache_clear(); mymodule_cache_clear();
} }
@ -1958,14 +1944,13 @@ function hook_modules_preenable($modules) {
* This function differs from hook_install() in that it gives all other modules * This function differs from hook_install() in that it gives all other modules
* a chance to perform actions when a module is installed, whereas * a chance to perform actions when a module is installed, whereas
* hook_install() is only called on the module actually being installed. See * hook_install() is only called on the module actually being installed. See
* module_enable() for a detailed description of the order in which install and * \Drupal\Core\Extension\ModuleHandler::install() for a detailed description of
* enable hooks are invoked. * the order in which install hooks are invoked.
* *
* @param $modules * @param $modules
* An array of the modules that were installed. * An array of the modules that were installed.
* *
* @see module_enable() * @see \Drupal\Core\Extension\ModuleHandler::install()
* @see hook_modules_enabled()
* @see hook_install() * @see hook_install()
*/ */
function hook_modules_installed($modules) { function hook_modules_installed($modules) {
@ -1975,45 +1960,13 @@ function hook_modules_installed($modules) {
} }
/** /**
* Perform necessary actions after modules are enabled. * Perform necessary actions before a module is uninstalled.
* *
* This function differs from hook_enable() in that it gives all other modules a * @param string $module
* chance to perform actions when modules are enabled, whereas hook_enable() is * The name of the module about to be uninstalled.
* only called on the module actually being enabled. See module_enable() for a
* detailed description of the order in which install and enable hooks are
* invoked.
*
* @param $modules
* An array of the modules that were enabled.
*
* @see hook_enable()
* @see hook_modules_installed()
* @see module_enable()
*/ */
function hook_modules_enabled($modules) { function hook_module_preuninstall($module) {
if (in_array('lousy_module', $modules)) { mymodule_cache_clear();
drupal_set_message(t('mymodule is not compatible with lousy_module'), 'error');
mymodule_disable_functionality();
}
}
/**
* Perform necessary actions after modules are disabled.
*
* This function differs from hook_disable() in that it gives all other modules
* a chance to perform actions when modules are disabled, whereas hook_disable()
* is only called on the module actually being disabled.
*
* @param $modules
* An array of the modules that were disabled.
*
* @see hook_disable()
* @see hook_modules_uninstalled()
*/
function hook_modules_disabled($modules) {
if (in_array('lousy_module', $modules)) {
mymodule_enable_functionality();
}
} }
/** /**
@ -2327,9 +2280,9 @@ function hook_requirements($phase) {
* .module file is needed, it may be loaded with drupal_load(). * .module file is needed, it may be loaded with drupal_load().
* *
* The tables declared by this hook will be automatically created when the * The tables declared by this hook will be automatically created when the
* module is first enabled, and removed when the module is uninstalled. This * module is installed, and removed when the module is uninstalled. This happens
* happens before hook_install() is invoked, and after hook_uninstall() is * before hook_install() is invoked, and after hook_uninstall() is invoked,
* invoked, respectively. * respectively.
* *
* By declaring the tables used by your module via an implementation of * By declaring the tables used by your module via an implementation of
* hook_schema(), these tables will be available on all supported database * hook_schema(), these tables will be available on all supported database
@ -2501,11 +2454,10 @@ function hook_query_TAG_alter(Drupal\Core\Database\Query\AlterableInterface $que
* *
* Implementations of this hook are by convention declared in the module's * Implementations of this hook are by convention declared in the module's
* .install file. The implementation can rely on the .module file being loaded. * .install file. The implementation can rely on the .module file being loaded.
* The hook will only be called the first time a module is enabled or after it * The hook will only be called when a module is installed. The module's schema
* is re-enabled after being uninstalled. The module's schema version will be * version will be set to the module's greatest numbered update hook. Because of
* set to the module's greatest numbered update hook. Because of this, any time * this, any time a hook_update_N() is added to the module, this function needs
* a hook_update_N() is added to the module, this function needs to be updated * to be updated to reflect the current version of the database schema.
* to reflect the current version of the database schema.
* *
* See the @link http://drupal.org/node/146843 Schema API documentation @endlink * See the @link http://drupal.org/node/146843 Schema API documentation @endlink
* for details on hook_schema and how database tables are defined. * for details on hook_schema and how database tables are defined.
@ -2519,9 +2471,7 @@ function hook_query_TAG_alter(Drupal\Core\Database\Query\AlterableInterface $que
* be removed during uninstall should be removed with hook_uninstall(). * be removed during uninstall should be removed with hook_uninstall().
* *
* @see hook_schema() * @see hook_schema()
* @see module_enable() * @see \Drupal\Core\Extension\ModuleHandler::install()
* @see hook_enable()
* @see hook_disable()
* @see hook_uninstall() * @see hook_uninstall()
* @see hook_modules_installed() * @see hook_modules_installed()
*/ */
@ -2764,35 +2714,6 @@ function hook_uninstall() {
variable_del('upload_file_types'); variable_del('upload_file_types');
} }
/**
* Perform necessary actions after module is enabled.
*
* The hook is called every time the module is enabled. It should be
* implemented in the module's .install file. The implementation can
* rely on the .module file being loaded.
*
* @see module_enable()
* @see hook_install()
* @see hook_modules_enabled()
*/
function hook_enable() {
mymodule_cache_rebuild();
}
/**
* Perform necessary actions before module is disabled.
*
* The hook is called every time the module is disabled. It should be
* implemented in the module's .install file. The implementation can rely
* on the .module file being loaded.
*
* @see hook_uninstall()
* @see hook_modules_disabled()
*/
function hook_disable() {
mymodule_cache_rebuild();
}
/** /**
* Return an array of tasks to be performed by an installation profile. * Return an array of tasks to be performed by an installation profile.
* *

View File

@ -513,6 +513,25 @@ function system_requirements($phase) {
$requirements['update status']['title'] = t('Update notifications'); $requirements['update status']['title'] = t('Update notifications');
} }
// Ensure that if upgrading from 7 to 8 we have no disabled modules.
if ($phase == 'update' && db_table_exists('system')) {
$modules = db_query('SELECT name, info FROM {system} WHERE type = :module AND status = 0 AND schema_version <> :schema_uninstalled', array(
':module' => 'module',
':schema_uninstalled' => SCHEMA_UNINSTALLED,
))->fetchAllKeyed(0, 1);
array_walk($modules, function (&$value, $key) {
$info = unserialize($value);
$value = $info['name'];
});
if (!empty($modules)) {
$requirements['disabled_modules'] = array(
'severity' => REQUIREMENT_ERROR,
'title' => t('Disabled modules'),
'value' => format_plural(count($modules), 'The %modules module is disabled.', 'The following modules are disabled: %modules', array('%modules' => implode(', ', $modules))),
'description' => t('Drupal 8 no longer supports disabled modules. Please either enable or uninstall them before upgrading.'),
);
}
}
return $requirements; return $requirements;
} }
@ -1531,7 +1550,7 @@ function system_update_8020() {
->condition('aid', 'system_block_ip_action') ->condition('aid', 'system_block_ip_action')
->execute(); ->execute();
// Enable the new Ban module. // Enable the new Ban module.
module_enable(array('ban')); Drupal::moduleHandler()->install(array('ban'));
} }
else { else {
// Drop old table. // Drop old table.
@ -1544,7 +1563,7 @@ function system_update_8020() {
*/ */
function system_update_8021() { function system_update_8021() {
// Enable the module without re-installing the schema. // Enable the module without re-installing the schema.
module_enable(array('action')); Drupal::moduleHandler()->install(array('action'));
// Rename former System module actions. // Rename former System module actions.
$map = array( $map = array(
'system_message_action' => 'action_message_action', 'system_message_action' => 'action_message_action',
@ -1845,7 +1864,7 @@ function system_update_8041() {
* Enable the new Entity module. * Enable the new Entity module.
*/ */
function system_update_8042() { function system_update_8042() {
module_enable(array('entity')); Drupal::moduleHandler()->install(array('entity'));
} }
/** /**
@ -1959,7 +1978,7 @@ function system_update_8047() {
*/ */
function system_update_8048() { function system_update_8048() {
// Enable the module without re-installing the schema. // Enable the module without re-installing the schema.
module_enable(array('menu_link')); Drupal::moduleHandler()->install(array('menu_link'));
// Add the langcode column if it doesn't exist. // Add the langcode column if it doesn't exist.
if (!db_field_exists('menu_inks', 'langcode')) { if (!db_field_exists('menu_inks', 'langcode')) {
@ -2228,7 +2247,6 @@ function system_update_8058() {
); );
db_change_field('menu_links', 'module', 'module', $spec); db_change_field('menu_links', 'module', 'module', $spec);
} }
} }
/** /**

View File

@ -116,7 +116,7 @@ function system_help($path, $arg) {
} }
return $output; return $output;
case 'admin/modules/uninstall': case 'admin/modules/uninstall':
return '<p>' . t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it on the main <a href="@modules">Modules page</a>.', array('@modules' => url('admin/modules'))) . '</p>'; return '<p>' . t('The uninstall process removes all data related to a module.') . '</p>';
case 'admin/structure/block/manage': case 'admin/structure/block/manage':
if ($arg[4] == 'system' && $arg[5] == 'powered-by') { if ($arg[4] == 'system' && $arg[5] == 'powered-by') {
return '<p>' . t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') . '</p>'; return '<p>' . t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') . '</p>';
@ -2328,7 +2328,7 @@ function system_check_directory($form_element) {
/** /**
* Returns an array of information about enabled modules or themes. * Returns an array of information about enabled modules or themes.
* *
* This function returns the contents of the .info.yml file for each enabled * This function returns the contents of the .info.yml file for each installed
* module or theme. * module or theme.
* *
* @param $type * @param $type
@ -2485,13 +2485,11 @@ function system_rebuild_module_data() {
$files = array(); $files = array();
ksort($modules); ksort($modules);
// Add name, status, weight, and schema version. // Add name, status, weight, and schema version.
$enabled_modules = (array) \Drupal::config('system.module')->get('enabled'); $installed_modules = (array) \Drupal::config('system.module')->get('enabled');
$disabled_modules = (array) \Drupal::config('system.module.disabled')->get();
$all_modules = $enabled_modules + $disabled_modules;
foreach ($modules as $module => $record) { foreach ($modules as $module => $record) {
$record->name = $module; $record->name = $module;
$record->weight = isset($all_modules[$module]) ? $all_modules[$module] : 0; $record->weight = isset($installed_modules[$module]) ? $installed_modules[$module] : 0;
$record->status = (int) isset($enabled_modules[$module]); $record->status = (int) isset($installed_modules[$module]);
$record->schema_version = SCHEMA_UNINSTALLED; $record->schema_version = SCHEMA_UNINSTALLED;
$files[$module] = $record->filename; $files[$module] = $record->filename;
} }

View File

@ -8,11 +8,11 @@
/** /**
* Implements hook_watchdog(). * Implements hook_watchdog().
* *
* This hook is called during module_enable() and since this hook * This hook is called during \Drupal\Core\Extension\ModuleHandler::install()
* implementation is invoked, we have to expect that this module and dependent * and since this hook implementation is invoked, we have to expect that this
* modules have been properly installed already. So we expect to be able to * module and dependent modules have been properly installed already. So we
* retrieve the entity information that has been registered by the required * expect to be able to retrieve the entity information that has been registered
* dependency module. * by the required dependency module.
* *
* @see EnableDisableTestCase::testEntityCache() * @see EnableDisableTestCase::testEntityCache()
*/ */

View File

@ -31,12 +31,3 @@ function module_test_install() {
$record = array('data' => 'Data inserted in hook_install()'); $record = array('data' => 'Data inserted in hook_install()');
drupal_write_record('module_test', $record); drupal_write_record('module_test', $record);
} }
/**
* Implements hook_enable().
*/
function module_test_enable() {
$record = array('data' => 'Data inserted in hook_enable()');
drupal_write_record('module_test', $record);
}

View File

@ -150,21 +150,12 @@ function module_test_class_loading() {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_modules_installed().
*/ */
function module_test_modules_enabled($modules) { function module_test_modules_installed($modules) {
// Record the ordered list of modules that were passed in to this hook so we // Record the ordered list of modules that were passed in to this hook so we
// can check that the modules were enabled in the correct sequence. // can check that the modules were enabled in the correct sequence.
\Drupal::state()->set('system_test.module_enable_order', $modules); \Drupal::state()->set('module_test.install_order', $modules);
}
/**
* Implements hook_modules_disabled().
*/
function module_test_modules_disabled($modules) {
// Record the ordered list of modules that were passed in to this hook so we
// can check that the modules were disabled in the correct sequence.
\Drupal::state()->set('module_test.disable_order', $modules);
} }
/** /**

View File

@ -97,28 +97,6 @@ function system_test_modules_installed($modules) {
} }
} }
/**
* Implements hook_modules_enabled().
*/
function system_test_modules_enabled($modules) {
if (\Drupal::state()->get('system_test.verbose_module_hooks')) {
foreach ($modules as $module) {
drupal_set_message(t('hook_modules_enabled fired for @module', array('@module' => $module)));
}
}
}
/**
* Implements hook_modules_disabled().
*/
function system_test_modules_disabled($modules) {
if (\Drupal::state()->get('system_test.verbose_module_hooks')) {
foreach ($modules as $module) {
drupal_set_message(t('hook_modules_disabled fired for @module', array('@module' => $module)));
}
}
}
/** /**
* Implements hook_modules_uninstalled(). * Implements hook_modules_uninstalled().
*/ */
@ -280,3 +258,17 @@ function system_test_authorize_init_page($page_title) {
system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title); system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title);
return new RedirectResponse($authorize_url); return new RedirectResponse($authorize_url);
} }
/**
* Implements hook_module_preinstall().
*/
function system_test_module_preinstall($module) {
Drupal::state()->set('system_test_preinstall_module', $module);
}
/**
* Implements hook_module_preuninstall().
*/
function system_test_module_preuninstall($module) {
Drupal::state()->set('system_test_preuninstall_module', $module);
}

View File

@ -202,10 +202,9 @@ class VocabularyUnitTest extends TaxonomyTestBase {
); );
entity_create('field_instance', $this->instance_definition)->save(); entity_create('field_instance', $this->instance_definition)->save();
module_disable(array('taxonomy'));
require_once DRUPAL_ROOT . '/core/includes/install.inc'; require_once DRUPAL_ROOT . '/core/includes/install.inc';
module_uninstall(array('taxonomy')); module_uninstall(array('taxonomy'));
module_enable(array('taxonomy')); \Drupal::moduleHandler()->install(array('taxonomy'));
// Now create a vocabulary with the same name. All field instances // Now create a vocabulary with the same name. All field instances
// connected to this vocabulary name should have been removed when the // connected to this vocabulary name should have been removed when the

View File

@ -9,22 +9,6 @@ use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\DatabaseStorageController;
use Drupal\field\Entity\Field; use Drupal\field\Entity\Field;
/**
* Implements hook_uninstall().
*/
function taxonomy_uninstall() {
\Drupal::entityManager()->addNamespaces(new ArrayIterator(array(
'Drupal\taxonomy' => DRUPAL_ROOT . '/core/modules/taxonomy/lib',
)));
drupal_classloader_register('taxonomy', 'core/modules/taxonomy');
// Remove taxonomy_term bundles.
$config_names = config_get_storage_names_with_prefix('taxonomy.vocabulary.');
foreach ($config_names as $config_name) {
$vid = substr($config_name, strlen('taxonomy.vocabulary.'));
entity_invoke_bundle_hook('delete', 'taxonomy_term', $vid);
}
}
/** /**
* Implements hook_schema(). * Implements hook_schema().
*/ */

View File

@ -18,7 +18,7 @@
*/ */
function toolbar_update_8000() { function toolbar_update_8000() {
// Enable the modules without re-installing the schema. // Enable the modules without re-installing the schema.
module_enable(array('breakpoint')); Drupal::moduleHandler()->install(array('breakpoint'));
} }
/** /**

View File

@ -280,7 +280,7 @@ class TrackerTest extends WebTestBase {
* Tests that publish/unpublish works at admin/content/node. * Tests that publish/unpublish works at admin/content/node.
*/ */
function testTrackerAdminUnpublish() { function testTrackerAdminUnpublish() {
module_enable(array('views')); \Drupal::moduleHandler()->install(array('views'));
$admin_user = $this->drupalCreateUser(array('access content overview', 'administer nodes', 'bypass node access')); $admin_user = $this->drupalCreateUser(array('access content overview', 'administer nodes', 'bypass node access'));
$this->drupalLogin($admin_user); $this->drupalLogin($admin_user);

View File

@ -13,9 +13,9 @@ function tracker_uninstall() {
} }
/** /**
* Implements hook_enable(). * Implements hook_install().
*/ */
function tracker_enable() { function tracker_install() {
$max_nid = db_query('SELECT MAX(nid) FROM {node}')->fetchField(); $max_nid = db_query('SELECT MAX(nid) FROM {node}')->fetchField();
if ($max_nid != 0) { if ($max_nid != 0) {
\Drupal::state()->set('tracker.index_nid', $max_nid); \Drupal::state()->set('tracker.index_nid', $max_nid);

View File

@ -66,7 +66,7 @@ class UserCancelTest extends WebTestBase {
* administer the site. * administer the site.
*/ */
function testUserCancelUid1() { function testUserCancelUid1() {
module_enable(array('views')); \Drupal::moduleHandler()->install(array('views'));
// Update uid 1's name and password to we know it. // Update uid 1's name and password to we know it.
$password = user_password(); $password = user_password();
$account = array( $account = array(
@ -275,7 +275,7 @@ class UserCancelTest extends WebTestBase {
*/ */
function testUserDelete() { function testUserDelete() {
\Drupal::config('user.settings')->set('cancel_method', 'user_cancel_delete')->save(); \Drupal::config('user.settings')->set('cancel_method', 'user_cancel_delete')->save();
module_enable(array('comment')); \Drupal::moduleHandler()->install(array('comment'));
$this->resetAll(); $this->resetAll();
// Create a user. // Create a user.
@ -390,7 +390,7 @@ class UserCancelTest extends WebTestBase {
* Create an administrative user and mass-delete other users. * Create an administrative user and mass-delete other users.
*/ */
function testMassUserCancelByAdmin() { function testMassUserCancelByAdmin() {
module_enable(array('views')); \Drupal::moduleHandler()->install(array('views'));
\Drupal::config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save(); \Drupal::config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
// Enable account cancellation notification. // Enable account cancellation notification.
\Drupal::config('user.settings')->set('notify.status_canceled', TRUE)->save(); \Drupal::config('user.settings')->set('notify.status_canceled', TRUE)->save();

View File

@ -122,7 +122,7 @@ class UserLoginTest extends WebTestBase {
// containing the necessary container builder code and then verify that the // containing the necessary container builder code and then verify that the
// users password gets rehashed during the login. // users password gets rehashed during the login.
$overridden_count_log2 = 19; $overridden_count_log2 = 19;
module_enable(array('user_custom_phpass_params_test')); \Drupal::moduleHandler()->install(array('user_custom_phpass_params_test'));
$account->pass_raw = $password; $account->pass_raw = $password;
$this->drupalLogin($account); $this->drupalLogin($account);

View File

@ -614,7 +614,7 @@ function user_update_8011() {
// User pictures can only be migrated to the new user picture image field // User pictures can only be migrated to the new user picture image field
// if Image module is installed. // if Image module is installed.
if (!module_exists('image')) { if (!module_exists('image')) {
$old_schema = module_enable(array('image')); $old_schema = Drupal::moduleHandler()->install(array('image'));
if ($old_schema['image'] == SCHEMA_UNINSTALLED) { if ($old_schema['image'] == SCHEMA_UNINSTALLED) {
// Install image.module with schema version 8002 as a previous version // Install image.module with schema version 8002 as a previous version
// would have to create tables that would be removed again. // would have to create tables that would be removed again.

View File

@ -52,7 +52,7 @@ abstract class ViewTestBase extends WebTestBase {
\Drupal::state()->set('views_test_data_schema', $this->schemaDefinition()); \Drupal::state()->set('views_test_data_schema', $this->schemaDefinition());
\Drupal::state()->set('views_test_data_views_data', $this->viewsData()); \Drupal::state()->set('views_test_data_views_data', $this->viewsData());
module_enable(array('views_test_data')); \Drupal::moduleHandler()->install(array('views_test_data'));
$this->resetAll(); $this->resetAll();
$this->rebuildContainer(); $this->rebuildContainer();
$this->container->get('module_handler')->reload(); $this->container->get('module_handler')->reload();

View File

@ -59,7 +59,7 @@ class DisplayPath extends UITestBase {
* Tests the menu and tab option form. * Tests the menu and tab option form.
*/ */
public function testMenuOptions() { public function testMenuOptions() {
$this->container->get('module_handler')->enable(array('menu')); $this->container->get('module_handler')->install(array('menu'));
$this->drupalGet('admin/structure/views/view/test_view'); $this->drupalGet('admin/structure/views/view/test_view');
// Add a new page display. // Add a new page display.

View File

@ -31,7 +31,7 @@ class PreviewTest extends UITestBase {
* Tests contextual links in the preview form. * Tests contextual links in the preview form.
*/ */
protected function testPreviewContextual() { protected function testPreviewContextual() {
module_enable(array('contextual')); \Drupal::moduleHandler()->install(array('contextual'));
$this->drupalGet('admin/structure/views/view/test_preview/edit'); $this->drupalGet('admin/structure/views/view/test_preview/edit');
$this->assertResponse(200); $this->assertResponse(200);
$this->drupalPostForm(NULL, $edit = array(), t('Update preview')); $this->drupalPostForm(NULL, $edit = array(), t('Update preview'));