diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 2590ce9..cb150b1 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -86,8 +86,10 @@ function entity_invoke_bundle_hook($hook, $entity_type, $bundle, $bundle_new = N // Notify the entity storage controller. $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. Drupal::moduleHandler()->invokeAll('entity_bundle_' . $hook, array($entity_type, $bundle, $bundle_new)); } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 0a2cb29..11c4a23 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -995,7 +995,7 @@ function install_base_system(&$install_state) { // Enable the user module so that sessions can be recorded during the // 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. // 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 // modules possibly depending on it can safely perform their installation // steps. - module_enable(array($module), FALSE); + Drupal::moduleHandler()->install(array($module), FALSE); $context['results'][] = $module; $context['message'] = t('Installed %module module.', array('%module' => $module_name)); } @@ -2528,7 +2528,7 @@ function install_configure_form_submit($form, &$form_state) { // Enable update.module if this option was selected. 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 // addresses to be notified when updates are available, if selected. diff --git a/core/includes/language.inc b/core/includes/language.inc index 44e91c1..ae7e1c2 100644 --- a/core/includes/language.inc +++ b/core/includes/language.inc @@ -203,8 +203,9 @@ function language_types_disable($types) { */ function language_types_set(array $configurable_language_types) { // Ensure that we are getting the defined language negotiation information. An - // invocation of module_enable() or module_disable() could outdate the cached - // information. + // invocation of \Drupal\Core\Extension\ModuleHandler::install() or + // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the + // cached information. drupal_static_reset('language_types_info'); drupal_static_reset('language_negotiation_info'); @@ -343,8 +344,9 @@ function language_negotiation_get_switch_links($type, $path) { */ function language_negotiation_purge() { // Ensure that we are getting the defined language negotiation information. An - // invocation of module_enable() or module_disable() could outdate the cached - // information. + // invocation of \Drupal\Core\Extension\ModuleHandler::install() or + // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the + // cached information. drupal_static_reset('language_negotiation_info'); drupal_static_reset('language_types_info'); diff --git a/core/includes/module.inc b/core/includes/module.inc index 1a32c09..af7ece1 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -201,32 +201,21 @@ function module_load_include($type, $module, $name = NULL) { return FALSE; } - /** - * Enables or installs a given list of modules. + * Installs a given list of modules. * * @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) { - return Drupal::moduleHandler()->enable($module_list, $enable_dependencies); -} - -/** - * Disables a given set of modules. - * - * @deprecated as of Drupal 8.0. Use - * Drupal::moduleHandler()->disable($module_list, $disable_dependents = TRUE). - */ -function module_disable($module_list, $disable_dependents = TRUE) { - Drupal::moduleHandler()->disable($module_list, $disable_dependents); + return Drupal::moduleHandler()->install($module_list, $enable_dependencies); } /** - * Uninstalls a given list of disabled modules. + * Uninstalls a given list of modules. * * @deprecated as of Drupal 8.0. Use - * Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents = TRUE). + * Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents = TRUE) */ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) { return Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents); @@ -332,7 +321,7 @@ function module_set_weight($module, $weight) { ->save(); // Prepare the new module list, sorted by weight, including filenames. - // @see module_enable() + // @see \Drupal\Core\Extension\ModuleHandler::install() $module_handler = Drupal::moduleHandler(); $current_module_filenames = $module_handler->getModuleList(); $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); return; } - $disabled_config = Drupal::config('system.module.disabled'); - if ($disabled_config->get($module) !== NULL) { - $disabled_config - ->set($module, $weight) - ->save(); - return; - } } /** diff --git a/core/includes/update.inc b/core/includes/update.inc index 4bd4e16..8374864 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -335,7 +335,6 @@ function update_prepare_d8_bootstrap() { } $module_config = Drupal::config('system.module'); - $disabled_modules = Drupal::config('system.module.disabled'); $theme_config = Drupal::config('system.theme'); $disabled_themes = Drupal::config('system.theme.disabled'); $schema_store = Drupal::keyValue('system.schema'); @@ -375,12 +374,9 @@ function update_prepare_d8_bootstrap() { } if ($record->type == 'module') { - if ($record->status && isset($module_data[$record->name])) { + if (isset($module_data[$record->name])) { $module_config->set('enabled.' . $record->name, $record->weight); } - else { - $disabled_modules->set($record->name, $record->weight); - } } elseif ($record->type == 'theme') { if ($record->status) { @@ -399,7 +395,6 @@ function update_prepare_d8_bootstrap() { $sorted_with_filenames[$m] = drupal_get_filename('module', $m); } Drupal::moduleHandler()->setModuleList($sorted_with_filenames); - $disabled_modules->save(); $theme_config->save(); $disabled_themes->save(); @@ -490,8 +485,7 @@ function update_prepare_stored_includes() { */ function update_prepare_d8_language() { if (db_table_exists('languages')) { - - module_enable(array('language')); + Drupal::moduleHandler()->install(array('language')); $languages = db_select('languages', '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 // picture upgrade path. - module_enable(array('file')); + Drupal::moduleHandler()->install(array('file')); $schema = array( 'description' => 'Generic key/value storage table with an expiration.', @@ -728,7 +722,7 @@ function update_fix_d8_requirements() { // Like any other module APIs and services, Views' services are not available // in update.php. Existing listings are migrated into configuration, using // 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); } diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php index 81fe970..92cf2a4 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -11,11 +11,10 @@ use Symfony\Component\Yaml\Parser; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\KeyValueStore\KeyValueStoreInterface; 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 { @@ -29,7 +28,7 @@ class ModuleHandler implements ModuleHandlerInterface { protected $loadedFiles; /** - * List of enabled modules. + * List of installed modules. * * @var array * 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. * * @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 * %container.modules% parameter being set up by DrupalKernel. * @@ -502,79 +501,72 @@ public static function parseDependency($dependency) { /** * {@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) { // Get all module data so we can find dependencies and sort. $module_data = system_rebuild_module_data(); - // Create an associative array with weights as values. - $module_list = array_flip(array_values($module_list)); + $module_list = $module_list ? array_combine($module_list, $module_list) : array(); + if (array_diff_key($module_list, $module_data)) { + // One or more of the given modules doesn't exist. + return FALSE; + } - while (list($module) = each($module_list)) { - if (!isset($module_data[$module])) { - // This module is not found in the filesystem, abort. - return FALSE; - } - if ($module_data[$module]->status) { - // Skip already enabled modules. - unset($module_list[$module]); - continue; - } - $module_list[$module] = $module_data[$module]->sort; + // Only process currently uninstalled modules. + $installed_modules = $module_config->get('enabled') ?: array(); + if (!$module_list = array_diff_key($module_list, $installed_modules)) { + // Nothing to do. All modules already installed. + return TRUE; + } - // Add dependencies to the list, with a placeholder weight. - // The new modules will be processed as the while loop continues. - foreach (array_keys($module_data[$module]->requires) as $dependency) { - if (!isset($module_list[$dependency])) { - $module_list[$dependency] = 0; + // 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; + } } } } - if (!$module_list) { - // Nothing to do. All modules already enabled. - return TRUE; - } + // 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 pre-calculated weights. + // Sort the module list by their weights (reverse). arsort($module_list); $module_list = array_keys($module_list); } - foreach ($module_list as $module) { - // Throw an exception if the module name is too long. - 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( - '%name' => $module, - '@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; + // Throw an exception if the module name is too long. + 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( + '%name' => $module, + '@max' => DRUPAL_EXTENSION_NAME_MAX_LENGTH, + ))); } + $module_config - ->set("enabled.$module", $weight) + ->set("enabled.$module", 0) ->set('enabled', module_config_sort($module_config->get('enabled'))) ->save(); - $disabled_config - ->clear($module) - ->save(); // Prepare the new module list, sorted by weight, including filenames. // This list is used for both the ModuleHandler and DrupalKernel. It needs @@ -591,12 +583,11 @@ public function enable($module_list, $enable_dependencies = TRUE) { $module_filenames = array(); foreach ($current_modules as $name => $weight) { if (isset($current_module_filenames[$name])) { - $filename = $current_module_filenames[$name]; + $module_filenames[$name] = $current_module_filenames[$name]; } 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. @@ -618,7 +609,7 @@ public function enable($module_list, $enable_dependencies = TRUE) { // taken over as %container.modules% parameter, which is passed to a fresh // ModuleHandler instance upon first retrieval. // @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); } @@ -628,47 +619,37 @@ public function enable($module_list, $enable_dependencies = TRUE) { drupal_theme_rebuild(); // 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. entity_info_cache_clear(); - // Now install the module if necessary. - if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) { - drupal_install_schema($module); + // Now install the module's schema if necessary. + drupal_install_schema($module); - // Set the schema version to the number of the last update provided - // by the module. - $versions = drupal_get_schema_versions($module); - $version = $versions ? max($versions) : SCHEMA_INSTALLED; + // Set the schema version to the number of the last update provided + // by the module. + $versions = drupal_get_schema_versions($module); + $version = $versions ? max($versions) : SCHEMA_INSTALLED; - // Install default configuration of the module. - config_install_default_config('module', $module); + // Install default configuration of the module. + config_install_default_config('module', $module); - // If the module has no current updates, but has some that were - // previously removed, set the version to the value of - // hook_update_last_removed(). - if ($last_removed = $this->invoke($module, 'update_last_removed')) { - $version = max($version, $last_removed); - } - drupal_set_installed_schema_version($module, $version); - // Allow the module to perform install tasks. - $this->invoke($module, 'install'); - // Record the fact that it was installed. - $modules_installed[] = $module; - watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO); + // If the module has no current updates, but has some that were + // previously removed, set the version to the value of + // hook_update_last_removed(). + if ($last_removed = $this->invoke($module, 'update_last_removed')) { + $version = max($version, $last_removed); } + drupal_set_installed_schema_version($module, $version); - // 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 installed. + $modules_installed[] = $module; - // Record the fact that it was enabled. - $modules_enabled[] = $module; - watchdog('system', '%module module enabled.', array('%module' => $module), WATCHDOG_INFO); + // Allow the module to perform install tasks. + $this->invoke($module, 'install'); + // Record the fact that it was installed. + watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO); } } @@ -677,195 +658,153 @@ public function enable($module_list, $enable_dependencies = TRUE) { $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; } /** * {@inheritdoc} */ - function disable($module_list, $disable_dependents = TRUE) { - if ($disable_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)); + public function uninstall(array $module_list, $uninstall_dependents = TRUE) { + // Get all module data so we can find dependencies and sort. + $module_data = system_rebuild_module_data(); + $module_list = $module_list ? array_combine($module_list, $module_list) : array(); + if (array_diff_key($module_list, $module_data)) { + // One or more of the given modules doesn't exist. + 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)) { - 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; + foreach (array_keys($module_data[$module]->required_by) as $dependent) { + if (!isset($module_data[$dependent])) { + // The dependent module does not exist. + return FALSE; + } - // 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; + // 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. - asort($module_list); - $module_list = array_keys($module_list); } - $invoke_modules = array(); + // Set the actual module weights. + $module_list = array_map(function ($module) use ($module_data) { + return $module_data[$module]->sort; + }, $module_list); - $module_config = \Drupal::config('system.module'); - $disabled_config = \Drupal::config('system.module.disabled'); + // Sort the module list by their weights. + asort($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'); 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'); + // Allow modules to react prior to the uninstallation of a module. + $this->invokeAll('module_preuninstall', array($module)); - $disabled_config - ->set($module, $module_config->get($module)) - ->save(); - $module_config - ->clear("enabled.$module") - ->save(); + // Uninstall the module. + module_load_install($module); + $this->invoke($module, 'uninstall'); + drupal_uninstall_schema($module); - // 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 all configuration belonging to the module. + config_uninstall_default_config('module', $module); - // Record the fact that it was disabled. - $invoke_modules[] = $module; - watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO); - } - } + // Remove the module's entry from the config. + $module_config->clear("enabled.$module")->save(); - if (!empty($invoke_modules)) { - // @todo Most of the following should happen in above loop already. + // 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); - // Refresh the system list to exclude the disabled modules. + // 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(); - // 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 kernel to exclude the uninstalled modules. + \Drupal::service('kernel')->updateModules($module_filenames, $module_filenames); - // Update the theme registry to remove the newly-disabled module. + // Update the theme registry to remove the newly uninstalled 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; - } - } - } + watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO); - // Sort the module list by pre-calculated weights. - asort($module_list); - $module_list = array_keys($module_list); + $schema_store->delete($module); } + drupal_get_installed_schema_version(NULL, TRUE); - $schema_store = \Drupal::keyValue('system.schema'); - $disabled_config = \Drupal::config('system.module.disabled'); - foreach ($module_list as $module) { - // Uninstall the module. - module_load_install($module); - $this->invoke($module, 'uninstall'); - drupal_uninstall_schema($module); + // Let other modules react. + $this->invokeAll('modules_uninstalled', array($module_list)); - // Remove all configuration belonging to the module. - config_uninstall_default_config('module', $module); + drupal_flush_all_caches(); + + return TRUE; + } - // Remove any cache bins defined by the module. - $service_yaml_file = drupal_get_path('module', $module) . "/$module.services.yml"; - if (file_exists($service_yaml_file)) { - $parser = new Parser; - $definitions = $parser->parse(file_get_contents($service_yaml_file)); - if (isset($definitions['services'])) { - foreach ($definitions['services'] as $id => $definition) { - if (isset($definition['tags'])) { - foreach ($definition['tags'] as $tag) { - // This works for the default cache registration and even in some - // cases when a non-default "super" factory is used. That should - // be extremely rare. - if ($tag['name'] == 'cache.bin' && isset($definition['factory_service']) && isset($definition['factory_method']) && !empty($definition['arguments'])) { - try { - $factory = \Drupal::service($definition['factory_service']); - if (method_exists($factory, $definition['factory_method'])) { - $backend = call_user_func_array(array($factory, $definition['factory_method']), $definition['arguments']); - if ($backend instanceof CacheBackendInterface) { - $backend->removeBin(); - } + /** + * 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"; + if (file_exists($service_yaml_file)) { + $parser = new Parser; + $definitions = $parser->parse(file_get_contents($service_yaml_file)); + if (isset($definitions['services'])) { + foreach ($definitions['services'] as $id => $definition) { + if (isset($definition['tags'])) { + foreach ($definition['tags'] as $tag) { + // This works for the default cache registration and even in some + // cases when a non-default "super" factory is used. That should + // be extremely rare. + if ($tag['name'] == 'cache.bin' && isset($definition['factory_service']) && isset($definition['factory_method']) && !empty($definition['arguments'])) { + try { + $factory = \Drupal::service($definition['factory_service']); + if (method_exists($factory, $definition['factory_method'])) { + $backend = call_user_func_array(array($factory, $definition['factory_method']), $definition['arguments']); + if ($backend instanceof CacheBackendInterface) { + $backend->removeBin(); } } - catch (\Exception $e) { - watchdog_exception('system', $e, 'Failed to remove cache bin defined by the service %id.', array('%id' => $id)); - } + } + catch (\Exception $e) { + watchdog_exception('system', $e, 'Failed to remove cache bin defined by the service %id.', array('%id' => $id)); } } } } } } - - 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; } /** diff --git a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php index b93e3e8..5a49e9e 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php @@ -253,77 +253,50 @@ public function invokeAll($hook, $args = array()); public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL); /** - * Enables or 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. + * Installs a given list of modules. * * Order of events: * - 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. - * - If the module is being enabled for the first time or had been - * uninstalled, invoke hook_install() and add it to the list of installed - * modules. - * - Invoke hook_enable(). + * - Invoke hook_install() and add it to the list of installed modules. * - Invoke hook_modules_installed(). - * - Invoke hook_modules_enabled(). * - * @param $module_list + * @param array $module_list * An array of module names. - * @param $enable_dependencies - * If TRUE, dependencies will automatically be added and enabled in the + * @param bool $enable_dependencies + * (optional) If TRUE, dependencies will automatically be installed 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. + * if you know $module_list is already complete. * - * @return + * @return bool * FALSE if one or more dependencies are missing, TRUE otherwise. * + * @see hook_module_preinstall() * @see hook_install() - * @see hook_enable() * @see hook_modules_installed() - * @see hook_modules_enabled() - */ - public function enable($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); + public function install(array $module_list, $enable_dependencies = TRUE); /** * Uninstalls a given list of disabled modules. * * @param array $module_list - * The modules to uninstall. It is the caller's responsibility to ensure that - * all modules in this list have already been disabled before this function - * is called. + * The modules to uninstall. * @param bool $uninstall_dependents - * (optional) If TRUE, the function will check that all modules which depend - * on the passed-in module list either are already uninstalled or contained in - * the list, and it will ensure that the modules are uninstalled 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. - * Defaults to TRUE. + * (optional) If TRUE, dependent modules will automatically be uninstalled + * in the correct order. This incurs a significant performance cost, so use + * FALSE if you know $module_list is already complete. * * @return bool - * Returns TRUE if the operation succeeds or FALSE if it aborts due to an - * unsafe condition, namely, $uninstall_dependents is TRUE and a module in - * $module_list has dependents which are not already uninstalled and not also - * included in $module_list). + * FALSE if one or more dependencies are missing, TRUE otherwise. + * + * @see hook_module_preuninstall() + * @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 diff --git a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php index 78553d9..5fcf990 100644 --- a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php @@ -58,7 +58,7 @@ public function getImplementations($hook) { /** * {@inheritdoc} */ - public function enable($module_list, $enable_dependencies = TRUE) { + public function install(array $module_list, $enable_dependencies = TRUE) { $schema_store = \Drupal::keyValue('system.schema'); $old_schema = array(); foreach ($module_list as $module) { @@ -74,16 +74,13 @@ public function enable($module_list, $enable_dependencies = TRUE) { db_create_table($table, $spec); } } + // Enable the module with a weight of 0. $module_config = \Drupal::config('system.module'); $module_config ->set("enabled.$module", 0) ->set('enabled', module_config_sort($module_config->get('enabled'))) ->save(); - // Ensure the module is not contained in disabled modules. - \Drupal::config('system.module.disabled') - ->clear($module) - ->save(); $current_schema = $schema_store->get($module); // Set the schema version if the module was not just disabled before. @@ -105,7 +102,7 @@ public function enable($module_list, $enable_dependencies = TRUE) { $module_config_path = drupal_get_path('module', $module) . '/config'; if (is_dir($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) { // If this file already exists, something in the upgrade path went // completely wrong and we want to know. @@ -134,14 +131,7 @@ public function enable($module_list, $enable_dependencies = TRUE) { /** * {@inheritdoc} */ - public function disable($module_list, $disable_dependents = TRUE) { - throw new \LogicException('Disabling modules is not supported during updates'); - } - - /** - * {@inheritdoc} - */ - public function uninstall($module_list = array(), $uninstall_dependents = TRUE) { + public function uninstall(array $module_list, $uninstall_dependents = TRUE) { throw new \LogicException('Uninstalling modules is not supported during updates'); } diff --git a/core/modules/action/lib/Drupal/action/Tests/ActionUninstallTest.php b/core/modules/action/lib/Drupal/action/Tests/ActionUninstallTest.php index 01b125d..d91b820 100644 --- a/core/modules/action/lib/Drupal/action/Tests/ActionUninstallTest.php +++ b/core/modules/action/lib/Drupal/action/Tests/ActionUninstallTest.php @@ -35,7 +35,6 @@ public static function getInfo() { * Tests Action uninstall. */ public function testActionUninstall() { - \Drupal::moduleHandler()->disable(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.' ); diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorConfigurationTest.php b/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorConfigurationTest.php index 59d5339..f2f9c5f 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorConfigurationTest.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorConfigurationTest.php @@ -59,7 +59,7 @@ function testSettingsPage() { // Make sure settings form is still accessible even after disabling a module // that provides the selected plugins. - module_disable(array('aggregator_test')); + module_uninstall(array('aggregator_test')); $this->resetAll(); $this->drupalGet('admin/config/services/aggregator/settings'); $this->assertResponse(200); diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Tests/UpdateFeedItemTest.php b/core/modules/aggregator/lib/Drupal/aggregator/Tests/UpdateFeedItemTest.php index 2cc1c8c..0c4f810 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Tests/UpdateFeedItemTest.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Tests/UpdateFeedItemTest.php @@ -72,7 +72,7 @@ function testUpdateFeedItem() { // Make sure updating items works even after disabling a module // that provides the selected plugins. $this->enableTestPlugins(); - module_disable(array('aggregator_test')); + module_uninstall(array('aggregator_test')); $this->updateFeedItems($feed); $this->assertResponse(200); } diff --git a/core/modules/block/block.install b/core/modules/block/block.install index 2c15a2a..e668961 100644 --- a/core/modules/block/block.install +++ b/core/modules/block/block.install @@ -184,7 +184,7 @@ function block_update_8005() { * Enable the Custom Block module. */ function block_update_8006() { - module_enable(array('custom_block')); + Drupal::moduleHandler()->install(array('custom_block')); } /** diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php index e90e407..369b496 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php @@ -238,7 +238,7 @@ function moveBlockToRegion(array $block, $region) { * Test _block_rehash(). */ function testBlockRehash() { - module_enable(array('block_test')); + \Drupal::moduleHandler()->install(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. @@ -267,100 +267,4 @@ function testBlockRehash() { $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->drupalPost('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->drupalPost('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, - ))); - } - } - } diff --git a/core/modules/breakpoint/breakpoint.install b/core/modules/breakpoint/breakpoint.install index dcc0b35..b0ea7f7 100644 --- a/core/modules/breakpoint/breakpoint.install +++ b/core/modules/breakpoint/breakpoint.install @@ -6,15 +6,15 @@ */ /** - * Implements hook_enable(). + * Implements hook_install(). * * Import breakpoints from all enabled themes. */ -function breakpoint_enable() { +function breakpoint_install() { // Import breakpoints from themes. $themes = list_themes(); _breakpoint_theme_enabled(array_keys($themes)); // Import breakpoints from modules. - _breakpoint_modules_enabled(array_keys(Drupal::moduleHandler()->getModuleList())); + _breakpoint_modules_installed(array_keys(Drupal::moduleHandler()->getModuleList())); } diff --git a/core/modules/breakpoint/breakpoint.module b/core/modules/breakpoint/breakpoint.module index 1a4a80c..93901ae 100644 --- a/core/modules/breakpoint/breakpoint.module +++ b/core/modules/breakpoint/breakpoint.module @@ -62,7 +62,7 @@ function breakpoint_themes_disabled($theme_list) { } /** - * Implements hook_modules_enabled(). + * Implements hook_modules_installed(). * * @param array $modules * 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. */ -function breakpoint_modules_enabled($modules) { - _breakpoint_modules_enabled($modules); +function breakpoint_modules_installed($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 - * 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) { $media_queries = breakpoint_get_module_media_queries($module); _breakpoint_import_media_queries($module, $module, Breakpoint::SOURCE_TYPE_MODULE, $media_queries); diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php index dde38a0..e00af05 100644 --- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php +++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php @@ -118,10 +118,6 @@ public function testThemeBreakpointGroupModule() { theme_disable(array('breakpoint_test_theme')); $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. module_uninstall(array('breakpoint_theme_test')); $this->assertFalse(entity_load('breakpoint_group', $breakpoint_group_obj->id()), 'Breakpoint group is removed if module is uninstalled.'); diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorAdminTest.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorAdminTest.php index e0e3cac..5ec423c 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorAdminTest.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorAdminTest.php @@ -145,7 +145,7 @@ function testAdmin() { // Now enable the ckeditor_test module, which provides one configurable // 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->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)]'); diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorLoadingTest.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorLoadingTest.php index 89628ad..5e05e33 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorLoadingTest.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorLoadingTest.php @@ -119,7 +119,7 @@ function testLoading() { // NOTE: the tests in CKEditorTest already ensure that changing the // configuration also results in modified CKEditor configuration, so we // don't test that here. - module_enable(array('ckeditor_test')); + \Drupal::moduleHandler()->install(array('ckeditor_test')); $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions(); $editor->settings['toolbar']['buttons'][0][] = 'Llama'; $editor->save(); diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install index 04e1291..4fe0ccf 100644 --- a/core/modules/comment/comment.install +++ b/core/modules/comment/comment.install @@ -17,7 +17,6 @@ function comment_uninstall() { ))); drupal_classloader_register('comment', 'core/modules/comment'); foreach ($node_types as $node_type) { - entity_invoke_bundle_hook('delete', 'comment', 'comment_node_' . $node_type); variable_del('comment_' . $node_type); variable_del('comment_anonymous_' . $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. $query = db_select('node_field_data', 'n'); $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 - * is enabled. We use hook_modules_enabled() rather than hook_enable() so we can - * react to node types of existing modules, and those of modules being enabled - * both before and after the Comment module in the loop of module_enable(). + * is enabled. We use hook_modules_installed() rather than hook_install() so we + * can react to node types of existing modules, and those of modules being + * 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 * per-node-type customization of comment fields. Each one of these bundles @@ -68,7 +68,7 @@ function comment_enable() { * * @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. // hook_node_type_insert() is used to create body fields while the comment // module is enabled. diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php index f9d25f1..cbd08ad 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php @@ -61,31 +61,32 @@ function testCommentDefaultFields() { } /** - * 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. $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules')); $this->drupalLogin($this->admin_user); // Disable the comment module. $edit = array(); - $edit['modules[Core][comment][enable]'] = FALSE; - $this->drupalPost('admin/modules', $edit, t('Save configuration')); + $edit['uninstall[comment]'] = TRUE; + $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); + $this->drupalPost(NULL, array(), t('Uninstall')); $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). $edit = array(); $edit['modules[Core][book][enable]'] = 'book'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); - // Now enable the comment module. + // Now install the comment module. $edit = array(); $edit['modules[Core][comment][enable]'] = 'comment'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); $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. $book_node = $this->drupalCreateNode(array('type' => 'book')); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php index 127a611..67f0712 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php @@ -46,7 +46,6 @@ function testCommentUninstallWithField() { $this->assertNotNull($field, 'The comment_body field exists.'); // 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')); // Check that the field is now deleted. @@ -70,7 +69,6 @@ function testCommentUninstallWithoutField() { // Ensure that uninstallation succeeds even if the field has already been // deleted manually beforehand. - $this->container->get('module_handler')->disable(array('comment')); $this->container->get('module_handler')->uninstall(array('comment')); } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php index 5431a96..3bb7839 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallWebTest.php @@ -37,7 +37,7 @@ function testIntegrationModuleReinstallation() { $default_configuration_entity = 'config_test.dynamic.config_integration_test'; // 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. $config_static = \Drupal::config($default_config); @@ -46,7 +46,7 @@ function testIntegrationModuleReinstallation() { $this->assertIdentical($config_entity->isNew(), TRUE); // Install the integration module. - module_enable(array('config_integration_test')); + \Drupal::moduleHandler()->install(array('config_integration_test')); // Verify that default module config exists. $config_static = \Drupal::config($default_config); @@ -66,20 +66,7 @@ function testIntegrationModuleReinstallation() { // In other words: This test passes even without this reset, but it shouldn't. $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. - module_disable(array('config_integration_test')); module_uninstall(array('config_integration_test')); // Verify the integration module's config was uninstalled. @@ -92,7 +79,7 @@ function testIntegrationModuleReinstallation() { $this->assertIdentical($config_entity->get('label'), 'Customized integration config label'); // 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. $config_static = \Drupal::config($default_config); diff --git a/core/modules/editor/lib/Drupal/editor/Tests/EditorAdminTest.php b/core/modules/editor/lib/Drupal/editor/Tests/EditorAdminTest.php index 0bc89e1..23c2f3b 100644 --- a/core/modules/editor/lib/Drupal/editor/Tests/EditorAdminTest.php +++ b/core/modules/editor/lib/Drupal/editor/Tests/EditorAdminTest.php @@ -104,7 +104,7 @@ function testAddEditorToNewFormat() { * Enables the unicorn editor. */ protected function enableUnicornEditor() { - module_enable(array('editor_test')); + \Drupal::moduleHandler()->install(array('editor_test')); $this->rebuildContainer(); $this->resetAll(); } diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module index 8b70c47..fdf8fc5 100644 --- a/core/modules/entity/entity.module +++ b/core/modules/entity/entity.module @@ -156,3 +156,18 @@ function entity_entity_bundle_delete($entity_type, $bundle) { } 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); + } + } + } +} diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 33b4cb0..52f8b4d 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -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. 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. field_sync_field_status(); } diff --git a/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php b/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php deleted file mode 100644 index 7b021e2..0000000 --- a/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php +++ /dev/null @@ -1,55 +0,0 @@ - '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.'); - } -} diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php index b6697e7..ff1c584 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php @@ -46,7 +46,7 @@ function testImportCreateDefault() { // Enable field_test_config module and check that the field and instance // 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. $field = entity_load('field_entity', $field_id); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php index 9c433aa..fe97da2 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php @@ -191,7 +191,7 @@ function testInstanceDisabledEntityType() { entity_create('field_instance', $instance_definition); // 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.'); } diff --git a/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php index 0b5400d..12e12b5 100644 --- a/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php @@ -91,15 +91,7 @@ function testReEnabledField() { $this->drupalPost(NULL, $edit, t('Save')); $this->assertRaw(''); - // Disable the telephone module and re-enable it. - 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[und][0][value]", '', 'Widget found.'); - - // Test that the module can't be disabled from the UI while there is data + // Test that the module can't be uninstalled from the UI while there is data // for it's fields. $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules')); $this->drupalLogin($admin_user); diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install index e4b1e26..6e8ea21 100644 --- a/core/modules/forum/forum.install +++ b/core/modules/forum/forum.install @@ -17,12 +17,7 @@ function forum_install() { $locked = Drupal::state()->get('node.type.locked'); $locked['forum'] = 'forum'; Drupal::state()->set('node.type.locked', $locked); -} -/** - * Implements hook_enable(). - */ -function forum_enable() { // Create the forum vocabulary if it does not exist. // @todo Change Forum module so forum.settings can contain the vocabulary's // 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'); - 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 // default config is installed. field_info_cache_clear(); diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php index ff4d712..5f5e18f 100644 --- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php +++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php @@ -107,30 +107,6 @@ function setUp() { } /** - * 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->drupalPost('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->drupalPost('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. */ function testForum() { @@ -254,7 +230,7 @@ function testAddOrphanTopic() { $this->assertEqual(0, $nid_count, 'A forum node was not created when missing a forum vocabulary.'); // Reset the defaults for future tests. - module_enable(array('forum')); + \Drupal::moduleHandler()->install(array('forum')); } /** diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php index cce8db0..7243fa6 100644 --- a/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php +++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php @@ -38,7 +38,6 @@ function testForumUninstallWithField() { $this->assertNotNull($field, 'The taxonomy_forums field exists.'); // 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')); // Check that the field is now deleted. @@ -62,7 +61,6 @@ function testForumUninstallWithoutField() { // Ensure that uninstallation succeeds even if the field has already been // deleted manually beforehand. - $this->container->get('module_handler')->disable(array('forum')); $this->container->get('module_handler')->uninstall(array('forum')); } diff --git a/core/modules/language/language.install b/core/modules/language/language.install index 42f9c37..16d2180 100644 --- a/core/modules/language/language.install +++ b/core/modules/language/language.install @@ -21,6 +21,9 @@ function language_install() { module_load_include('inc', 'language', 'language.negotiation'); 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 // functions will not expect languages to be present. drupal_language_initialize(); -} - -/** - * 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 + // Force the language_count state to be 1, so that when checking if the // 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); } diff --git a/core/modules/language/language.module b/core/modules/language/language.module index 2dd5e57..27e62a7 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -725,9 +725,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'; // Load configurability options from configuration. language_types_set(array()); @@ -735,10 +735,10 @@ function language_modules_enabled($modules) { } /** - * Implements hook_modules_disabled(). + * Implements hook_modules_uninstalled(). */ -function language_modules_disabled($modules) { - language_modules_enabled($modules); +function language_modules_uninstalled($modules) { + language_modules_installed($modules); } /** diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php index 6ab71ba..18a4cd9 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php @@ -102,9 +102,9 @@ function testInfoAlterations() { $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. - $this->languageNegotiationUpdate('disable'); + $this->languageNegotiationUpdate('uninstall'); // Check that only the core language types are available. foreach (language_types_get_all() as $type) { @@ -128,25 +128,24 @@ function testInfoAlterations() { /** * Update language types/negotiation information. * - * Manually invoke language_modules_enabled()/language_modules_disabled() - * since they would not be invoked after enabling/disabling language_test the - * first time. + * Manually invoke language_modules_installed()/language_modules_uninstalled() + * since they would not be invoked after installing/uninstalling language_test + * the first time. */ - protected function languageNegotiationUpdate($op = 'enable') { + protected function languageNegotiationUpdate($op = 'install') { static $last_op = NULL; $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) { - $function = "module_{$op}"; - $function($modules); + call_user_func(array($this->container->get('module_handler'), $op), $modules); // Reset hook implementation cache. $this->container->get('module_handler')->resetImplementations(); } drupal_static_reset('language_types_info'); drupal_static_reset('language_negotiation_info'); - $function = "language_modules_{$op}d"; + $function = "language_modules_{$op}ed"; if (function_exists($function)) { $function($modules); } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php index aa53fbb..72ddbe5 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php @@ -138,8 +138,7 @@ function testConfigTranslation() { // Quick test to ensure translation file exists. $this->assertEqual(\Drupal::config('locale.config.xx.image.style.medium')->get('label'), $image_style_label); - // Disable and uninstall the module. - $this->drupalPost('admin/modules', array('modules[Core][image][enable]' => FALSE), t('Save configuration')); + // Uninstall the module. $this->drupalPost('admin/modules/uninstall', array('uninstall[image]' => "image"), t('Uninstall')); $this->drupalPost(NULL, array(), t('Uninstall')); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php index dc990e8..34bd2d6 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php @@ -214,7 +214,7 @@ function testContentTypeDirLang() { * Test filtering Node content by language. */ function testNodeAdminLanguageFilter() { - module_enable(array('views')); + \Drupal::moduleHandler()->install(array('views')); // User to add and remove language. $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access')); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php index 1cfb538..71a2043 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php @@ -109,7 +109,6 @@ function testUninstallProcess() { ->save(); // Uninstall Locale. - module_disable($locale_module); module_uninstall($locale_module); $this->rebuildContainer(); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php index 9f55abc..565d14c 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php @@ -332,7 +332,7 @@ function testUpdateImportModeNone() { /** * Tests automatic translation import when a module is enabled. */ - function testEnableDisableModule() { + function testEnableUninstallModule() { // Make the hidden test modules look like a normal custom module. \Drupal::state()->set('locale.test_system_info_alter', TRUE); @@ -350,11 +350,6 @@ function testEnableDisableModule() { array('%number' => 7, '%update' => 0, '%delete' => 0)), 'One translation file imported.'); $this->assertTranslation('Tuesday', 'Dienstag', 'de'); - // Disable and uninstall a module. - $edit = array( - 'modules[Testing][locale_test_translate][enable]' => FALSE, - ); - $this->drupalPost('admin/modules', $edit, t('Save configuration')); $edit = array( 'uninstall[locale_test_translate]' => 1, ); @@ -375,7 +370,7 @@ function testEnableDisableModule() { * enabled modules and will import them. When a language is removed the system * 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. \Drupal::state()->set('locale.test_system_info_alter', TRUE); diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuUninstallTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuUninstallTest.php index 203768b..6815f02 100644 --- a/core/modules/menu/lib/Drupal/menu/Tests/MenuUninstallTest.php +++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuUninstallTest.php @@ -33,7 +33,6 @@ public static function getInfo() { * Tests Menu uninstall. */ public function testMenuUninstall() { - \Drupal::moduleHandler()->disable(array('menu')); \Drupal::moduleHandler()->uninstall(array('menu')); $this->assertTrue(entity_load('menu', 'admin', TRUE), 'The \'admin\' menu still exists after uninstalling menu module.'); diff --git a/core/modules/menu/menu.install b/core/modules/menu/menu.install index 36e6302..9480d89 100644 --- a/core/modules/menu/menu.install +++ b/core/modules/menu/menu.install @@ -8,6 +8,41 @@ 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(). */ function menu_uninstall() { diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module index 57f39b6..17dc649 100644 --- a/core/modules/menu/menu.module +++ b/core/modules/menu/menu.module @@ -177,42 +177,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. * * @param $menu_name diff --git a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php index 593093a..cd117bb 100644 --- a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php @@ -52,7 +52,7 @@ public function testImportCreateDefault() { // Enable node_test_config module and check that the content type // 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); $this->assertTrue($node_type, 'The default content type was created.'); } diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAdminTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAdminTest.php index 1af4979..6b517fd 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeAdminTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeAdminTest.php @@ -49,7 +49,7 @@ function testContentAdminSort() { // Create nodes that have different node.changed values. $this->container->get('state')->set('node_test.storage_controller', TRUE); - module_enable(array('node_test')); + \Drupal::moduleHandler()->install(array('node_test')); $changed = REQUEST_TIME; foreach (array('dd', 'aa', 'DD', 'bb', 'cc', 'CC', 'AA', 'BB') as $prefix) { $changed += 1000; diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php index 22aedb4..c311bd7 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php @@ -50,24 +50,7 @@ function testNodeTypeCustomizationPersistence() { $this->drupalGet('node/add'); $this->assertText($description, 'Customized description found'); - // Disable forum and check that the node type gets disabled. - $this->drupalPost('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->drupalPost('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->drupalPost('admin/modules', $forum_disable, t('Save configuration')); + // Uninstall forum. $edit = array('uninstall[forum]' => 'forum'); $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); $this->drupalPost(NULL, array(), t('Uninstall')); diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php index c9e8345..9eec51b 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php @@ -134,7 +134,7 @@ function testNodeTypeEditing() { */ function testNodeTypeStatus() { // 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(); foreach (array('book', 'article', 'page') as $type) { $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type))); @@ -143,14 +143,14 @@ function testNodeTypeStatus() { // Disable book module and the respective type should still be active, since // 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(); $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['page']->isLocked(), 'Basic page node type still active.'); - // Re-enable the modules and verify that the types are active again. - $this->container->get('module_handler')->enable(array('book'), FALSE); + // Re-install the modules and verify that the types are active again. + $this->container->get('module_handler')->install(array('book'), FALSE); $types = node_type_get_types(); foreach (array('book', 'article', 'page') as $type) { $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type))); @@ -192,10 +192,9 @@ function testNodeTypeDeletion() { ); $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. - $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->assertResponse(403); - $this->container->get('module_handler')->disable(array('forum')); $this->container->get('module_handler')->uninstall(array('forum')); $this->drupalGet('admin/structure/types/manage/forum/delete'); $this->assertResponse(200); diff --git a/core/modules/node/node.install b/core/modules/node/node.install index 02cc7a0..a2efaaf 100644 --- a/core/modules/node/node.install +++ b/core/modules/node/node.install @@ -696,7 +696,7 @@ function node_update_8011() { */ function node_update_8012() { // Enable the history module without re-installing the schema. - module_enable(array('history')); + Drupal::moduleHandler()->install(array('history')); } /** diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 5b448f4..02c5a09 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -1288,27 +1288,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(). * * Checks the content type specific visibility settings and removes the block @@ -1946,7 +1925,7 @@ function node_access_needs_rebuild($rebuild = NULL) { * rebuild only once he is done. * * 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 * (optional) Set to TRUE to process in 'batch' mode, spawning processing over @@ -2098,9 +2077,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 // be rebuilt. if (!node_access_needs_rebuild() && array_intersect($modules, Drupal::moduleHandler()->getImplementations('node_grants'))) { @@ -2109,9 +2088,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(), // in which case the node access table needs to be rebuilt. foreach ($modules as $module) { @@ -2208,7 +2203,7 @@ function node_library_info() { */ function node_system_info_alter(&$info, $file, $type) { if ($type == 'module' && $file->name == 'translation') { - $info['hidden'] = !module_exists('translation') && Drupal::config('system.module.disabled')->get('translation') === NULL; + $info['hidden'] = !module_exists('translation'); } } diff --git a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.install b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.install new file mode 100644 index 0000000..c8643a1 --- /dev/null +++ b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.install @@ -0,0 +1,43 @@ + '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(); +} diff --git a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module index c285204..84a5fbe 100644 --- a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module +++ b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module @@ -42,39 +42,3 @@ function node_access_test_language_node_access_records(EntityInterface $node) { } 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(); -} diff --git a/core/modules/overlay/overlay.install b/core/modules/overlay/overlay.install index 29e6fa9..f3b78f3 100644 --- a/core/modules/overlay/overlay.install +++ b/core/modules/overlay/overlay.install @@ -6,12 +6,12 @@ */ /** - * Implements hook_enable(). + * Implements hook_install(). * * If the module is being enabled through the admin UI, and not from an * installation profile, reopen the modules page in an overlay. */ -function overlay_enable() { +function overlay_install() { if (strpos(current_path(), 'admin/modules') === 0) { // Flag for a redirect to #overlay=admin/modules on hook_init(). $_SESSION['overlay_enable_redirect'] = 1; diff --git a/core/modules/php/php.install b/core/modules/php/php.install index a88fe6a..8acf925 100644 --- a/core/modules/php/php.install +++ b/core/modules/php/php.install @@ -6,8 +6,8 @@ */ /** - * Implements hook_disable(). + * Implements hook_uninstall(). */ -function php_disable() { +function php_uninstall() { drupal_set_message(t('The PHP module has been disabled. Any existing content that was using the PHP filter will now be visible in plain text. This might pose a security risk by exposing sensitive information, if any, used in the PHP code.')); } diff --git a/core/modules/rest/lib/Drupal/rest/Tests/NodeTest.php b/core/modules/rest/lib/Drupal/rest/Tests/NodeTest.php index cd453e5..76773df 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/NodeTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/NodeTest.php @@ -50,7 +50,7 @@ protected function enableNodeConfiguration($method, $operation) { */ public function testNodes() { // 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'); $node = $this->entityCreate('node'); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php index b55feee..9b40ce5 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php @@ -162,9 +162,9 @@ public function containerBuild(ContainerBuilder $container) { // 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 // service but when a test is happy with the superminimal container put - // together here, it still might a keyvalue storage for anything (for - // eg. module_enable) using \Drupal::state() -- that's why a memory - // service was added in the first place. + // together here, it still might a keyvalue storage for anything using + // \Drupal::state() -- that's why a memory service was added in the first + // place. $container ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory') ->addArgument(new Reference('service_container')); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php index 505ff33..bd48b1c 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php @@ -89,7 +89,7 @@ function testEnableModulesInstall() { $this->assertFalse($schema, "'$table' table schema not found."); // Install the module. - module_enable(array($module)); + \Drupal::moduleHandler()->install(array($module)); // Verify that the enabled module exists. $this->assertTrue(module_exists($module), "$module module found."); @@ -198,6 +198,9 @@ function testInstallConfig() { * Tests that the module list is retained after enabling/installing/disabling. */ function testEnableModulesFixedList() { + // Install system module. + $this->container->get('module_handler')->install(array('system')); + // entity_test is loaded via $modules; its entity type should exist. $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $this->assertTrue(TRUE == entity_get_info('entity_test')); @@ -208,12 +211,12 @@ function testEnableModulesFixedList() { $this->assertTrue(TRUE == entity_get_info('entity_test')); // 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->assertTrue(TRUE == entity_get_info('entity_test')); - // Disable one of those modules; entity_test should still exist. - module_disable(array('field_test')); + // Uninstall one of those modules; entity_test should still exist. + $this->container->get('module_handler')->uninstall(array('field_test')); $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $this->assertTrue(TRUE == entity_get_info('entity_test')); @@ -222,7 +225,7 @@ function testEnableModulesFixedList() { $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE); $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')); // Create a field and an instance. diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 5e32613..54252f0 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -827,7 +827,7 @@ protected function setUp() { } if ($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->rebuildContainer(); } diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesListConfirmForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesListConfirmForm.php index d674b18..be0ec46 100644 --- a/core/modules/system/lib/Drupal/system/Form/ModulesListConfirmForm.php +++ b/core/modules/system/lib/Drupal/system/Form/ModulesListConfirmForm.php @@ -115,18 +115,11 @@ public function buildForm(array $form, array &$form_state) { // were not manually selected. foreach ($this->modules['dependencies'] as $module => $dependencies) { $items[] = format_plural(count($dependencies), 'You must enable the @required module to install @module.', 'You must enable the @required modules to install @module.', array( - '@module' => $this->modules['enable'][$module], + '@module' => $this->modules['install'][$module], '@required' => implode(', ', $dependencies), )); } - foreach ($this->modules['missing'] as $name => $dependents) { - $items[] = format_plural(count($dependents), 'The @module module is missing, so the following module will be disabled: @depends.', 'The @module module is missing, so the following modules will be disabled: @depends.', array( - '@module' => $name, - '@depends' => implode(', ', $dependents), - )); - } - $form['message'] = array( '#theme' => 'item_list', '#items' => $items, @@ -146,12 +139,9 @@ public function submitForm(array &$form, array &$form_state) { // Gets list of modules prior to install process. $before = $this->moduleHandler->getModuleList(); - // Installs, enables, and disables modules. - if (!empty($this->modules['enable'])) { - $this->moduleHandler->enable(array_keys($this->modules['enable'])); - } - if (!empty($this->modules['disable'])) { - $this->moduleHandler->disable(array_keys($this->modules['disable'])); + // Install the given modules. + if (!empty($this->modules['install'])) { + $this->moduleHandler->install(array_keys($this->modules['install'])); } // Gets module list after install process, flushes caches and displays a diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php index ffe1253..7972819 100644 --- a/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php +++ b/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php @@ -14,7 +14,7 @@ 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 * each module's name, description, and information about which modules it @@ -117,7 +117,7 @@ public function buildForm(array $form, array &$form_state) { '#title' => $this->t($package), '#theme' => 'system_modules_details', '#header' => array( - array('data' => '' . $this->t('Enabled') . '', 'class' => array('checkbox')), + array('data' => '' . $this->t('Installed') . '', 'class' => array('checkbox')), array('data' => $this->t('Name'), 'class' => array('name')), array('data' => $this->t('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)), ), @@ -206,8 +206,9 @@ protected function buildRow(array $modules, $module, $distribution) { // Present a checkbox for installing and indicating the status of a module. $row['enable'] = array( '#type' => 'checkbox', - '#title' => $this->t('Enable'), + '#title' => $this->t('Install'), '#default_value' => (bool) $module->status, + '#disabled' => (bool) $module->status, ); // Disable the checkbox for required modules. @@ -301,67 +302,47 @@ protected function buildRow(array $modules, $module, $distribution) { } /** - * 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 * The form state 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) { $packages = $form_state['values']['modules']; - // Build a list of modules to enable or disable. + // Build a list of modules to install. $modules = array( - 'enable' => array(), - 'disable' => array(), + 'install' => 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. $data = system_rebuild_module_data(); foreach ($data as $name => $module) { - // Modules with missing dependencies have to be disabled. - if ($this->moduleHandler->moduleExists($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']; + if (!empty($module->required) && !$this->moduleHandler->moduleExists($name)) { + $modules['install'][$name] = $module->info['name']; } } // First, build a list of all modules that were selected. foreach ($packages as $items) { foreach ($items as $name => $checkbox) { - // Do not override modules that are forced to be enabled/disabled. - if (isset($modules['enable'][$name]) || isset($modules['disable'][$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']; + if ($checkbox['enable'] && !$this->moduleHandler->moduleExists($name)) { + $modules['install'][$name] = $data[$name]->info['name']; } } } // Add all dependencies to a list. - while (list($module) = each($modules['enable'])) { + while (list($module) = each($modules['install'])) { 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['enable'][$dependency] = $data[$dependency]->info['name']; + $modules['install'][$dependency] = $data[$dependency]->info['name']; } } } @@ -371,11 +352,11 @@ protected function buildModuleList(array $form_state) { // Invoke hook_requirements('install'). If failures are detected, make // sure the dependent modules aren't installed either. - foreach (array_keys($modules['enable']) as $module) { - if (drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED && !drupal_check_module($module)) { - unset($modules['enable'][$module]); + foreach (array_keys($modules['install']) as $module) { + if (!drupal_check_module($module)) { + unset($modules['install'][$module]); foreach (array_keys($data[$module]->required_by) as $dependent) { - unset($modules['enable'][$dependent]); + unset($modules['install'][$dependent]); unset($modules['dependencies'][$dependent]); } } @@ -388,11 +369,12 @@ protected function buildModuleList(array $form_state) { * {@inheritdoc} */ 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); - // Check if we have to enable any dependencies. If there is one or more - // dependencies that are not enabled yet, redirect to the confirmation form. + // Check if we have to install any dependencies. If there is one or more + // dependencies that are not installed yet, redirect to the confirmation + // form. if (!empty($modules['dependencies']) || !empty($modules['missing'])) { // Write the list of changed module states into a key value store. $account = $this->getCurrentUser()->id(); @@ -410,11 +392,8 @@ public function submitForm(array &$form, array &$form_state) { $before = $this->moduleHandler->getModuleList(); // There seem to be no dependencies that would need approval. - if (!empty($modules['enable'])) { - $this->moduleHandler->enable(array_keys($modules['enable'])); - } - if (!empty($modules['disable'])) { - $this->moduleHandler->disable(array_keys($modules['disable'])); + if (!empty($modules['install'])) { + $this->moduleHandler->install(array_keys($modules['install'])); } // Gets module list after install process, flushes caches and displays a diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php index 33e402b..af1fb21 100644 --- a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php +++ b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php @@ -70,15 +70,15 @@ public function buildForm(array $form, array &$form_state) { // Get a list of disabled, installed modules. $modules = system_rebuild_module_data(); - $disabled = array_filter($modules, function ($module) { - return empty($module->status) && drupal_get_installed_schema_version($module->name) > SCHEMA_UNINSTALLED; + $uninstallable = array_filter($modules, function ($module) use ($modules) { + return empty($modules[$module->name]->info['required']) && drupal_get_installed_schema_version($module->name) > SCHEMA_UNINSTALLED; }); $form['modules'] = array(); // Only build the rest of the form if there are any modules available to // uninstall; - if (empty($disabled)) { + if (empty($uninstallable)) { return $form; } @@ -86,10 +86,10 @@ public function buildForm(array $form, array &$form_state) { // Sort all modules by their name. $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); - foreach ($disabled as $module) { + foreach ($uninstallable as $module) { $name = $module->info['name'] ?: $module->name; $form['modules'][$module->name]['#module_name'] = $name; $form['modules'][$module->name]['name']['#markup'] = $name; @@ -107,7 +107,7 @@ public function buildForm(array $form, array &$form_state) { foreach (array_keys($module->required_by) as $dependent) { if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) { $name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent; - $form['modules'][$module->name]['#dependents'][] = $name; + $form['modules'][$module->name]['#required_by'][] = $name; $form['uninstall'][$module->name]['#disabled'] = TRUE; } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php index cf7d9cf..4e45336 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php @@ -26,7 +26,7 @@ public static function getInfo() { * Ensures entity info cache is updated after changes. */ function testEntityInfoChanges() { - module_enable(array('entity_cache_test')); + \Drupal::moduleHandler()->install(array('entity_cache_test')); $entity_info = entity_get_info(); $this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.'); @@ -39,8 +39,8 @@ function testEntityInfoChanges() { $info = entity_get_info('entity_cache_test'); $this->assertEqual($info['label'], 'New label.', 'New label appears in entity info.'); - // Disable the providing module and make sure the entity type is gone. - module_disable(array('entity_cache_test', 'entity_cache_test_dependency')); + // Uninstall the providing module and make sure the entity type is gone. + module_uninstall(array('entity_cache_test', 'entity_cache_test_dependency')); $entity_info = entity_get_info(); $this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.'); } @@ -51,7 +51,7 @@ function testEntityInfoChanges() { * @see entity_cache_test_watchdog() */ function testEntityInfoCacheWatchdog() { - module_enable(array('entity_cache_test')); + \Drupal::moduleHandler()->install(array('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['controllers']['storage'], 'Drupal\Core\Entity\DatabaseStorageController', 'Entity controller class info is correct.'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php index 2705aed..e3510f6 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php @@ -75,7 +75,7 @@ function testLanguageSelectElementOptions() { function testHiddenLanguageSelectElement() { // Disable the language module, so that the language select field will not // be rendered. - module_disable(array('language')); + module_uninstall(array('language')); $this->drupalGet('form-test/language_select'); // 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'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php index 2fd8eb9..71f29d4 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php @@ -34,7 +34,7 @@ public static function getInfo() { */ function testClassLoading() { // 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(); // Check twice to test an unprimed and primed system_list() cache. for ($i=0; $i<2; $i++) { @@ -50,7 +50,7 @@ function testClassLoading() { */ function testClassLoadingDisabledModules() { // Ensure that module_autoload_test is disabled. - module_disable(array('module_autoload_test'), FALSE); + module_uninstall(array('module_autoload_test'), FALSE); $this->resetAll(); // Check twice to test an unprimed and primed system_list() cache. for ($i=0; $i<2; $i++) { diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php index 59dc6a2..83030e1 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php @@ -54,20 +54,6 @@ function testMissingModules() { $this->assertRaw(t('@module (missing)', 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]"]'); $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->drupalPost('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->drupalPost(NULL, NULL, t('Continue')); - - // Verify that the module has been disabled. - $this->assertModules(array('system_dependencies_test'), FALSE); } /** @@ -103,7 +89,7 @@ function testIncompatibleCoreVersionDependency() { * Tests enabling a module that depends on a module which fails hook_requirements(). */ function testEnableRequirementsFailureDependency() { - module_enable(array('comment')); + \Drupal::moduleHandler()->install(array('comment')); $this->assertModules(array('requirements1_test'), FALSE); $this->assertModules(array('requirements2_test'), FALSE); @@ -130,7 +116,7 @@ function testEnableRequirementsFailureDependency() { * UI. Dependencies should be enabled before their dependents. */ function testModuleEnableOrder() { - module_enable(array('module_test'), FALSE); + \Drupal::moduleHandler()->install(array('module_test'), FALSE); $this->resetAll(); $this->assertModules(array('module_test'), TRUE); \Drupal::state()->set('module_test.dependency', 'dependency'); @@ -161,7 +147,7 @@ function testModuleEnableOrder() { $this->assertModules(array('forum', 'ban', 'php', 'datetime', 'comment', 'history', 'taxonomy', 'options', 'number'), TRUE); // 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); } @@ -175,14 +161,6 @@ function testUninstallDependents() { $this->drupalPost(NULL, array(), t('Continue')); $this->assertModules(array('forum'), TRUE); - // Disable forum and comment. Both should now be installed but disabled. - $edit = array('modules[Core][forum][enable]' => FALSE); - $this->drupalPost('admin/modules', $edit, t('Save configuration')); - $this->assertModules(array('forum'), FALSE); - $edit = array('modules[Core][comment][enable]' => FALSE); - $this->drupalPost('admin/modules', $edit, t('Save configuration')); - $this->assertModules(array('comment'), FALSE); - // Check that the taxonomy module cannot be uninstalled. $this->drupalGet('admin/modules/uninstall'); $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php deleted file mode 100644 index 8458bc7..0000000 --- a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php +++ /dev/null @@ -1,226 +0,0 @@ - '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->drupalPost('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->drupalPost(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->drupalPost('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->drupalPost('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->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); - $this->drupalPost(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); - } -} diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/InstallTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/InstallTest.php index a141f00..43eec4f 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/InstallTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/InstallTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Module; +use Drupal\Core\Extension\ExtensionNameLengthException; use Drupal\simpletest\WebTestBase; /** @@ -41,11 +42,58 @@ public static function getInfo() { * that modules are fully functional while Drupal is installing and enabling * them. */ - function testDrupalWriteRecord() { + public function testDrupalWriteRecord() { // Check for data that was inserted using drupal_write_record() while the // 'module_test' module was being installed and enabled. $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_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); + } + } + } diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/InstallUninstallTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/InstallUninstallTest.php new file mode 100644 index 0000000..9bb77a8 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Module/InstallUninstallTest.php @@ -0,0 +1,178 @@ + '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->drupalPost('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->drupalPost(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->drupalPost('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->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); + $this->drupalPost(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); + } + +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php index d2d65bc..ee303e4 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php @@ -43,7 +43,7 @@ function testModuleList() { $this->assertModuleList($module_list, t('Standard profile')); // Try to install a new module. - module_enable(array('ban')); + \Drupal::moduleHandler()->install(array('ban')); $module_list[] = 'ban'; sort($module_list); $this->assertModuleList($module_list, t('After adding a module')); @@ -98,18 +98,18 @@ function testModuleImplements() { $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 - // name. The subsequent module_enable() below will only call into - // setModuleList(), but will not explicitly reset the hook implementation - // cache, as that is expected to happen implicitly by setting the module - // list. This verifies that the hook implementation cache is cleared - // whenever setModuleList() is called. + // name. The subsequent \Drupal\Core\Extension\ModuleHandler::install() + // below will only call into setModuleList(), but will not explicitly reset + // the hook implementation cache, as that is expected to happen implicitly + // by setting the module list. This verifies that the hook implementation + // cache is cleared whenever setModuleList() is called. $module_handler = \Drupal::moduleHandler(); $module_handler->invokeAll('test'); // Make sure group include files are detected properly even when the file is // already loaded when the cache is rebuilt. // 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_load_include('inc', 'module_test', 'module_test.file'); $modules = $module_handler->getImplementations('test_hook'); @@ -120,7 +120,7 @@ function testModuleImplements() { * Test that module_invoke() can load a hook defined in hook_hook_info(). */ function testModuleInvoke() { - module_enable(array('module_test'), FALSE); + \Drupal::moduleHandler()->install(array('module_test'), FALSE); $this->resetAll(); $this->drupalGet('module-test/hook-dynamic-loading-invoke'); $this->assertText('success!', 'module_invoke() dynamically loads a hook defined in hook_hook_info().'); @@ -130,7 +130,7 @@ function testModuleInvoke() { * Test that module_invoke_all() can load a hook defined in hook_hook_info(). */ function testModuleInvokeAll() { - module_enable(array('module_test'), FALSE); + \Drupal::moduleHandler()->install(array('module_test'), FALSE); $this->resetAll(); $this->drupalGet('module-test/hook-dynamic-loading-invoke-all'); $this->assertText('success!', 'module_invoke_all() dynamically loads a hook defined in hook_hook_info().'); @@ -143,7 +143,7 @@ function testModuleInvokeAll() { * functions execute early in the request handling. */ function testModuleInvokeAllDuringLoadFunction() { - module_enable(array('module_test'), FALSE); + \Drupal::moduleHandler()->install(array('module_test'), FALSE); $this->resetAll(); $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().'); @@ -156,7 +156,7 @@ function testDependencyResolution() { // 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 // 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->assertFalse(module_exists('forum'), 'Forum module is disabled.'); $this->assertFalse(module_exists('ban'), 'Ban module is disabled.'); @@ -166,53 +166,24 @@ function testDependencyResolution() { // depends on a made-up module, foo. Nothing should be installed. \Drupal::state()->set('module_test.dependency', 'missing dependency'); drupal_static_reset('system_rebuild_module_data'); - $result = module_enable(array('forum')); - $this->assertFalse($result, 'module_enable() returns FALSE if dependencies are missing.'); - $this->assertFalse(module_exists('forum'), 'module_enable() aborts if dependencies are missing.'); + $result = \Drupal::moduleHandler()->install(array('forum')); + $this->assertFalse($result, '\Drupal\Core\Extension\ModuleHandler::install() returns FALSE 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 - // depends on the PHP module. module_enable() should work. + // depends on the PHP module. + // \Drupal\Core\Extension\ModuleHandler::install() should work. \Drupal::state()->set('module_test.dependency', 'dependency'); drupal_static_reset('system_rebuild_module_data'); - $result = module_enable(array('forum')); - $this->assertTrue($result, 'module_enable() returns the correct value.'); + $result = \Drupal::moduleHandler()->install(array('forum')); + $this->assertTrue($result, '\Drupal\Core\Extension\ModuleHandler::install() returns the correct value.'); // Verify that the fake dependency chain was installed. - $this->assertTrue(module_exists('ban') && module_exists('php'), 'Dependency chain was installed by module_enable().'); + $this->assertTrue(module_exists('ban') && module_exists('php'), 'Dependency chain was installed by \Drupal\Core\Extension\ModuleHandler::install().'); // Verify that the original module was installed. $this->assertTrue(module_exists('forum'), 'Module installation with unlisted dependencies succeeded.'); // Finally, verify that the modules were enabled in the correct order. - $module_order = \Drupal::state()->get('system_test.module_enable_order') ?: array(); - $this->assertEqual($module_order, array('php', 'ban', 'forum'), 'Modules were enabled in the correct order by module_enable().'); - - // Now, disable the PHP module. Both forum and ban should be disabled as - // well, in the correct order. - module_disable(array('php')); - $this->assertTrue(!module_exists('forum') && !module_exists('ban'), 'Depedency chain was disabled by module_disable().'); - $this->assertFalse(module_exists('php'), 'Disabling a module with unlisted dependents succeeded.'); - $disabled_modules = \Drupal::state()->get('module_test.disable_order') ?: array(); - $this->assertEqual($disabled_modules, array('forum', 'ban', 'php'), '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 PHP 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('php')); - $this->assertFalse($result, 'Calling module_uninstall() on a module whose dependents are not uninstalled fails.'); - foreach (array('forum', 'ban', 'php') as $module) { - $this->assertNotEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was not uninstalled.', array('@module' => $module))); - } + $module_order = \Drupal::state()->get('module_test.install_order') ?: array(); + $this->assertEqual($module_order, array('php', 'ban', 'forum'), 'Modules were enabled in the correct order by \Drupal\Core\Extension\ModuleHandler::install().'); // Now uninstall all three modules explicitly, but in the incorrect order, // and make sure that drupal_uninstal_modules() uninstalled them in the @@ -232,28 +203,28 @@ function testDependencyResolution() { $this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, 'Comment module was uninstalled.'); $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->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 // php module. But, this time do it with ban module declaring a dependency // on a specific version of php module in its info file. Make sure that - // module_enable() still works. + // \Drupal\Core\Extension\ModuleHandler::install() still works. \Drupal::state()->set('module_test.dependency', 'version dependency'); drupal_static_reset('system_rebuild_module_data'); - $result = module_enable(array('forum')); - $this->assertTrue($result, 'module_enable() returns the correct value.'); + $result = \Drupal::moduleHandler()->install(array('forum')); + $this->assertTrue($result, '\Drupal\Core\Extension\ModuleHandler::install() returns the correct value.'); // Verify that the fake dependency chain was installed. - $this->assertTrue(module_exists('ban') && module_exists('php'), 'Dependency chain was installed by module_enable().'); + $this->assertTrue(module_exists('ban') && module_exists('php'), 'Dependency chain was installed by \Drupal\Core\Extension\ModuleHandler::install().'); // Verify that the original module was installed. $this->assertTrue(module_exists('forum'), 'Module installation with version dependencies succeeded.'); // 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(); $php_position = array_search('php', $enable_order); $ban_position = array_search('ban', $enable_order); $forum_position = array_search('forum', $enable_order); $php_before_ban = $php_position !== FALSE && $ban_position !== FALSE && $php_position < $ban_position; $ban_before_forum = $ban_position !== FALSE && $forum_position !== FALSE && $ban_position < $forum_position; - $this->assertTrue($php_before_ban && $ban_before_forum, 'Modules were enabled in the correct order by module_enable().'); + $this->assertTrue($php_before_ban && $ban_before_forum, 'Modules were enabled in the correct order by \Drupal\Core\Extension\ModuleHandler::install().'); } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleEnableTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleEnableTest.php index d4967f8..e69de29 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleEnableTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleEnableTest.php @@ -1,73 +0,0 @@ - '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); - } - } - -} diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php index 78cecbf..de0e075 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php @@ -35,7 +35,6 @@ public static function getInfo() { function testUserPermsUninstalled() { // Uninstalls the module_test module, so hook_modules_uninstalled() // is executed. - module_disable(array('module_test')); module_uninstall(array('module_test')); // Are the perms defined by module_test removed? diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php index 7998af1..c48e8a2 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/VersionTest.php @@ -12,13 +12,6 @@ */ class VersionTest extends ModuleTestBase { - /** - * Modules to enable. - * - * @var array - */ - public static $modules = array('module_test'); - public static function getInfo() { return array( 'name' => 'Module versions', diff --git a/core/modules/system/lib/Drupal/system/Tests/ServiceProvider/ServiceProviderTest.php b/core/modules/system/lib/Drupal/system/Tests/ServiceProvider/ServiceProviderTest.php index bffd0f0..ffe398f 100644 --- a/core/modules/system/lib/Drupal/system/Tests/ServiceProvider/ServiceProviderTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/ServiceProvider/ServiceProviderTest.php @@ -46,12 +46,12 @@ function testServiceProviderRegistration() { * Tests that the DIC keeps up with module enable/disable in the same request. */ function testServiceProviderRegistrationDynamic() { - // Disable the module and ensure the service provider's service is not registered. - module_disable(array('service_provider_test')); + // Uninstall the module and ensure the service provider's service is not registered. + \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.'); - // Enable the module and ensure the service provider's service is registered. - module_enable(array('service_provider_test')); + // Install the module and ensure the service provider's service is registered. + \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.'); } diff --git a/core/modules/system/lib/Drupal/system/Tests/System/DefaultMobileMetaTagsTest.php b/core/modules/system/lib/Drupal/system/Tests/System/DefaultMobileMetaTagsTest.php index e5a3b98..ba0889f 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/DefaultMobileMetaTagsTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/DefaultMobileMetaTagsTest.php @@ -42,7 +42,7 @@ public function testDefaultMetaTagsExist() { * Verifies that the default mobile meta tags can be removed. */ public function testRemovingDefaultMetaTags() { - module_enable(array('system_module_test')); + \Drupal::moduleHandler()->install(array('system_module_test')); $this->drupalGet(''); foreach ($this->default_metatags as $name => $metatag) { $this->assertNoRaw($metatag, String::format('Default Mobile meta tag "@name" removed properly.', array('@name' => $name)), 'System'); diff --git a/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php b/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php index aa2e1ae..c739dd9 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php @@ -31,7 +31,7 @@ public static function getInfo() { function testSystemInfoAlter() { // Enable seven and the test module. 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.'); // Verify that the rebuilt and altered theme info is returned. @@ -44,19 +44,5 @@ function testSystemInfoAlter() { $this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was returned by system_list().'); $list_themes = 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().'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php b/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php index ae39a10..99af2dd 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php @@ -52,12 +52,13 @@ function setUp() { */ function testMainContentFallback() { $edit = array(); - // Disable the block module. - $edit['modules[Core][block][enable]'] = FALSE; - $this->drupalPost('admin/modules', $edit, t('Save configuration')); - $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); + // Uninstall the block module. + $edit['uninstall[block]'] = 'block'; + $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); + $this->drupalPost(NULL, NULL, t('Uninstall')); + $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.'); $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. $this->drupalGet('admin/config/system/site-information'); diff --git a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php index d3476f7..b584a33 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php @@ -254,7 +254,7 @@ function testSwitchDefaultTheme() { * Test that themes can't be enabled when the base theme or engine is missing. */ function testInvalidTheme() { - module_enable(array('theme_page_test')); + \Drupal::moduleHandler()->install(array('theme_page_test')); $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 theme engine @theme_engine to operate correctly.', array('@theme_engine' => 'not_real_engine')), 'Invalid theme engine check succeeded.'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php index a633558..5733ac3 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php @@ -219,29 +219,6 @@ function testThemeGetSetting() { } /** - * Ensures the theme registry is rebuilt when modules are disabled/enabled. - */ - function testRegistryRebuild() { - $this->assertIdentical(theme('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->assertIdentical(theme('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->assertIdentical(theme('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. */ function testDrupalRenderChildren() { diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php index 6aa50b2..64dc1ba 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php @@ -47,7 +47,7 @@ public function testDisabledUpgrade() { } } $to_enable = array_diff_key($available, $enabled); - module_enable(array_keys($to_enable)); + \Drupal::moduleHandler()->install(array_keys($to_enable)); // Check for updates. require_once DRUPAL_ROOT . '/core/includes/update.inc'; require_once DRUPAL_ROOT . '/core/includes/install.inc'; diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 9db20be..a1bedbd 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -641,11 +641,11 @@ function theme_system_modules_uninstall($variables) { // Display table. $rows = array(); foreach (element_children($form['modules']) as $module) { - if (!empty($form['modules'][$module]['#dependents'])) { - $disabled_message = format_plural(count($form['modules'][$module]['#dependents']), + if (!empty($form['modules'][$module]['#required_by'])) { + $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 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 = '
' . $disabled_message . '
'; } else { diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index d366e01..63d880c 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -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 $modules - * An array of modules about to be installed. - */ -function hook_modules_preinstall($modules) { - 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. + * @param string $module + * The name of the module about to be installed. */ -function hook_modules_preenable($modules) { +function hook_module_preinstall($module) { 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 * a chance to perform actions when a module is installed, whereas * 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 - * enable hooks are invoked. + * \Drupal\Core\Extension\ModuleHandler::install() for a detailed description of + * the order in which install hooks are invoked. * * @param $modules * An array of the modules that were installed. * - * @see module_enable() - * @see hook_modules_enabled() + * @see \Drupal\Core\Extension\ModuleHandler::install() * @see hook_install() */ function hook_modules_installed($modules) { @@ -1975,45 +1960,13 @@ function hook_modules_installed($modules) { } /** - * Perform necessary actions after modules are enabled. - * - * This function differs from hook_enable() in that it gives all other modules a - * chance to perform actions when modules are enabled, whereas hook_enable() is - * 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. + * Perform necessary actions before a module is uninstalled. * - * @see hook_enable() - * @see hook_modules_installed() - * @see module_enable() + * @param string $module + * The name of the module about to be uninstalled. */ -function hook_modules_enabled($modules) { - if (in_array('lousy_module', $modules)) { - 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(); - } +function hook_module_preuninstall($module) { + mymodule_cache_clear(); } /** @@ -2327,9 +2280,9 @@ function hook_requirements($phase) { * .module file is needed, it may be loaded with drupal_load(). * * The tables declared by this hook will be automatically created when the - * module is first enabled, and removed when the module is uninstalled. This - * happens before hook_install() is invoked, and after hook_uninstall() is - * invoked, respectively. + * module is installed, and removed when the module is uninstalled. This happens + * before hook_install() is invoked, and after hook_uninstall() is invoked, + * respectively. * * By declaring the tables used by your module via an implementation of * 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 * .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 - * is re-enabled after being uninstalled. The module's schema version will be - * set to the module's greatest numbered update hook. Because of this, any time - * a hook_update_N() is added to the module, this function needs to be updated - * to reflect the current version of the database schema. + * The hook will only be called when a module is installed. The module's schema + * version will be set to the module's greatest numbered update hook. Because of + * this, any time a hook_update_N() is added to the module, this function needs + * to be updated to reflect the current version of the database schema. * * See the @link http://drupal.org/node/146843 Schema API documentation @endlink * 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(). * * @see hook_schema() - * @see module_enable() - * @see hook_enable() - * @see hook_disable() + * @see \Drupal\Core\Extension\ModuleHandler::install() * @see hook_uninstall() * @see hook_modules_installed() */ @@ -2765,35 +2715,6 @@ function hook_uninstall() { } /** - * 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. * * Any tasks you define here will be run, in order, after the installer has diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 447320c..fe85f63 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1529,7 +1529,7 @@ function system_update_8020() { ->condition('aid', 'system_block_ip_action') ->execute(); // Enable the new Ban module. - module_enable(array('ban')); + Drupal::moduleHandler()->install(array('ban')); } else { // Drop old table. @@ -1542,7 +1542,7 @@ function system_update_8020() { */ function system_update_8021() { // Enable the module without re-installing the schema. - module_enable(array('action')); + Drupal::moduleHandler()->install(array('action')); // Rename former System module actions. $map = array( 'system_message_action' => 'action_message_action', @@ -1843,7 +1843,7 @@ function system_update_8041() { * Enable the new Entity module. */ function system_update_8042() { - module_enable(array('entity')); + Drupal::moduleHandler()->install(array('entity')); } /** @@ -1957,7 +1957,7 @@ function system_update_8047() { */ function system_update_8048() { // 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. if (!db_field_exists('menu_inks', 'langcode')) { @@ -2226,7 +2226,6 @@ function system_update_8058() { ); db_change_field('menu_links', 'module', 'module', $spec); } - } /** diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 39886f4..c002c71 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -116,7 +116,7 @@ function system_help($path, $arg) { } return $output; case 'admin/modules/uninstall': - return '

' . t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it on the main Modules page.', array('@modules' => url('admin/modules'))) . '

'; + return '

' . t('The uninstall process removes all data related to a module.') . '

'; case 'admin/structure/block/manage': if ($arg[4] == 'system' && $arg[5] == 'powered-by') { return '

' . t('The Powered by Drupal 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.') . '

'; @@ -2346,7 +2346,7 @@ function system_check_directory($form_element) { /** * 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. * * @param $type @@ -2501,13 +2501,11 @@ function system_rebuild_module_data() { $files = array(); ksort($modules); // Add name, status, weight, and schema version. - $enabled_modules = (array) Drupal::config('system.module')->get('enabled'); - $disabled_modules = (array) Drupal::config('system.module.disabled')->get(); - $all_modules = $enabled_modules + $disabled_modules; + $installed_modules = (array) Drupal::config('system.module')->get('enabled'); foreach ($modules as $module => $record) { $record->name = $module; - $record->weight = isset($all_modules[$module]) ? $all_modules[$module] : 0; - $record->status = (int) isset($enabled_modules[$module]); + $record->weight = isset($installed_modules[$module]) ? $installed_modules[$module] : 0; + $record->status = (int) isset($installed_modules[$module]); $record->schema_version = SCHEMA_UNINSTALLED; $files[$module] = $record->filename; } diff --git a/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module b/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module index 962114c..19d4a55 100644 --- a/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module +++ b/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module @@ -8,11 +8,11 @@ /** * Implements hook_watchdog(). * - * This hook is called during module_enable() and since this hook - * implementation is invoked, we have to expect that this module and dependent - * modules have been properly installed already. So we expect to be able to - * retrieve the entity information that has been registered by the required - * dependency module. + * This hook is called during \Drupal\Core\Extension\ModuleHandler::install() + * and since this hook implementation is invoked, we have to expect that this + * module and dependent modules have been properly installed already. So we + * expect to be able to retrieve the entity information that has been registered + * by the required dependency module. * * @see EnableDisableTestCase::testEntityCache() */ diff --git a/core/modules/system/tests/modules/module_test/module_test.install b/core/modules/system/tests/modules/module_test/module_test.install index 4cc09df..f3b274a 100644 --- a/core/modules/system/tests/modules/module_test/module_test.install +++ b/core/modules/system/tests/modules/module_test/module_test.install @@ -31,12 +31,3 @@ function module_test_install() { $record = array('data' => 'Data inserted in hook_install()'); 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); -} - diff --git a/core/modules/system/tests/modules/module_test/module_test.module b/core/modules/system/tests/modules/module_test/module_test.module index fd1d2e6..bfbad0d 100644 --- a/core/modules/system/tests/modules/module_test/module_test.module +++ b/core/modules/system/tests/modules/module_test/module_test.module @@ -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 // can check that the modules were enabled in the correct sequence. - Drupal::state()->set('system_test.module_enable_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); + Drupal::state()->set('module_test.install_order', $modules); } /** diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module index ea10a04..2e749d9 100644 --- a/core/modules/system/tests/modules/system_test/system_test.module +++ b/core/modules/system/tests/modules/system_test/system_test.module @@ -98,28 +98,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(). */ function system_test_modules_uninstalled($modules) { @@ -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); 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); +} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php index fe2bce0..33c49cd 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php @@ -202,10 +202,9 @@ function testUninstallReinstall() { ); entity_create('field_instance', $this->instance_definition)->save(); - module_disable(array('taxonomy')); require_once DRUPAL_ROOT . '/core/includes/install.inc'; module_uninstall(array('taxonomy')); - module_enable(array('taxonomy')); + \Drupal::moduleHandler()->install(array('taxonomy')); // Now create a vocabulary with the same name. All field instances // connected to this vocabulary name should have been removed when the diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install index 7648ba0..8819541 100644 --- a/core/modules/taxonomy/taxonomy.install +++ b/core/modules/taxonomy/taxonomy.install @@ -10,22 +10,6 @@ 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(). */ function taxonomy_schema() { diff --git a/core/modules/toolbar/toolbar.install b/core/modules/toolbar/toolbar.install index 3d4f517..4b03662 100644 --- a/core/modules/toolbar/toolbar.install +++ b/core/modules/toolbar/toolbar.install @@ -18,7 +18,7 @@ */ function toolbar_update_8000() { // Enable the modules without re-installing the schema. - module_enable(array('breakpoint')); + Drupal::moduleHandler()->install(array('breakpoint')); } /** diff --git a/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php b/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php index b11df97..4020fd3 100644 --- a/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php +++ b/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php @@ -257,7 +257,7 @@ function testTrackerCronIndexing() { * Tests that publish/unpublish works at admin/content/node. */ function testTrackerAdminUnpublish() { - module_enable(array('views')); + \Drupal::moduleHandler()->install(array('views')); $admin_user = $this->drupalCreateUser(array('access content overview', 'administer nodes', 'bypass node access')); $this->drupalLogin($admin_user); diff --git a/core/modules/tracker/tracker.install b/core/modules/tracker/tracker.install index 841d74a..6858a5d 100644 --- a/core/modules/tracker/tracker.install +++ b/core/modules/tracker/tracker.install @@ -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(); if ($max_nid != 0) { Drupal::state()->set('tracker.index_nid', $max_nid); diff --git a/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php b/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php index af8d8c9..fd152ee 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php @@ -67,7 +67,7 @@ function testUserCancelWithoutPermission() { * administer the site. */ function testUserCancelUid1() { - module_enable(array('views')); + \Drupal::moduleHandler()->install(array('views')); // Update uid 1's name and password to we know it. $password = user_password(); $account = array( @@ -276,7 +276,7 @@ function testUserAnonymize() { */ function testUserDelete() { \Drupal::config('user.settings')->set('cancel_method', 'user_cancel_delete')->save(); - module_enable(array('comment')); + \Drupal::moduleHandler()->install(array('comment')); $this->resetAll(); // Create a user. @@ -392,7 +392,7 @@ function testUserWithoutEmailCancelByAdmin() { * Create an administrative user and mass-delete other users. */ function testMassUserCancelByAdmin() { - module_enable(array('views')); + \Drupal::moduleHandler()->install(array('views')); \Drupal::config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save(); // Enable account cancellation notification. \Drupal::config('user.settings')->set('notify.status_canceled', TRUE)->save(); diff --git a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php index fa657c9..4441df9 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php @@ -122,7 +122,7 @@ function testPasswordRehashOnLogin() { // containing the necessary container builder code and then verify that the // users password gets rehashed during the login. $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; $this->drupalLogin($account); diff --git a/core/modules/user/user.install b/core/modules/user/user.install index 2d5b03e..ab2cc3f 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -614,7 +614,7 @@ function user_update_8011() { // User pictures can only be migrated to the new user picture image field // if Image module is installed. if (!module_exists('image')) { - $old_schema = module_enable(array('image')); + $old_schema = Drupal::moduleHandler()->install(array('image')); if ($old_schema['image'] == SCHEMA_UNINSTALLED) { // Install image.module with schema version 8002 as a previous version // would have to create tables that would be removed again. diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php b/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php index a4c8567..67e84a6 100644 --- a/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php +++ b/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php @@ -52,7 +52,7 @@ protected function enableViewsTestModule() { \Drupal::state()->set('views_test_data_schema', $this->schemaDefinition()); \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->rebuildContainer(); $this->container->get('module_handler')->reload(); diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php b/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php index 8f63b66..f8bc35a 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php @@ -59,7 +59,7 @@ public function testDeleteWithNoPath() { * Tests the menu and tab option form. */ 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'); // Add a new page display. diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Tests/PreviewTest.php b/core/modules/views_ui/lib/Drupal/views_ui/Tests/PreviewTest.php index 6ed0640..c9b019c 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/Tests/PreviewTest.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/Tests/PreviewTest.php @@ -31,7 +31,7 @@ public static function getInfo() { * Tests contextual links in the preview form. */ protected function testPreviewContextual() { - module_enable(array('contextual')); + \Drupal::moduleHandler()->install(array('contextual')); $this->drupalGet('admin/structure/views/view/test_preview/edit'); $this->assertResponse(200); $this->drupalPost(NULL, $edit = array(), t('Update preview'));