Index: includes/install.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/install.inc,v retrieving revision 1.70 diff -u -p -r1.70 install.inc --- includes/install.inc 20 Sep 2008 20:22:23 -0000 1.70 +++ includes/install.inc 23 Sep 2008 20:31:06 -0000 @@ -483,7 +483,10 @@ function drupal_install_modules($module_ } while ($moved); asort($module_list); $module_list = array_keys($module_list); - array_filter($module_list, '_drupal_install_module'); + $modules_installed = array_filter($module_list, '_drupal_install_module'); + if (!empty($modules_installed)) { + module_invoke_all('modules_installed', $module_installed); + } module_enable($module_list); } @@ -551,46 +554,52 @@ function drupal_install_system() { module_rebuild_cache(); } - /** * Calls the uninstall function and updates the system table for a given module. * - * @param $module - * The machine name of the module to uninstall. + * @param $module_list + * The modules to uninstall. */ -function drupal_uninstall_module($module) { - // First, retrieve all the module's menu paths from db. - drupal_load('module', $module); - $paths = module_invoke($module, 'menu'); - - // Uninstall the module(s). - module_load_install($module); - module_invoke($module, 'uninstall'); - - // Now remove the menu links for all paths declared by this module. - if (!empty($paths)) { - $paths = array_keys($paths); - // Clean out the names of load functions. - foreach ($paths as $index => $path) { - $parts = explode('/', $path, MENU_MAX_PARTS); - foreach ($parts as $k => $part) { - if (preg_match('/^%[a-z_]*$/', $part)) { - $parts[$k] = '%'; +function drupal_uninstall_modules($module_list = array()) { + foreach ($module_list as $module) { + // First, retrieve all the module's menu paths from db. + drupal_load('module', $module); + $paths = module_invoke($module, 'menu'); + + // Uninstall the module. + module_load_install($module); + module_invoke($module, 'uninstall'); + + // Now remove the menu links for all paths declared by this module. + if (!empty($paths)) { + $paths = array_keys($paths); + // Clean out the names of load functions. + foreach ($paths as $index => $path) { + $parts = explode('/', $path, MENU_MAX_PARTS); + foreach ($parts as $k => $part) { + if (preg_match('/^%[a-z_]*$/', $part)) { + $parts[$k] = '%'; + } } + $paths[$index] = implode('/', $parts); } - $paths[$index] = implode('/', $parts); - } - $placeholders = implode(', ', array_fill(0, count($paths), "'%s'")); + $placeholders = implode(', ', array_fill(0, count($paths), "'%s'")); - $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN (' . $placeholders . ') AND external = 0 ORDER BY depth DESC', $paths); - // Remove all such items. Starting from those with the greatest depth will - // minimize the amount of re-parenting done by menu_link_delete(). - while ($item = db_fetch_array($result)) { - _menu_delete_item($item, TRUE); + $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN (' . $placeholders . ') AND external = 0 ORDER BY depth DESC', $paths); + // Remove all such items. Starting from those with the greatest depth will + // minimize the amount of re-parenting done by menu_link_delete(). + while ($item = db_fetch_array($result)) { + _menu_delete_item($item, TRUE); + } } + + drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED); } - drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED); + if (!empty($module_list)) { + // Call hook_module_uninstall to let other modules act + module_invoke_all('modules_uninstalled', $module_list); + } } /** Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.126 diff -u -p -r1.126 module.inc --- includes/module.inc 20 Sep 2008 20:22:23 -0000 1.126 +++ includes/module.inc 23 Sep 2008 20:31:14 -0000 @@ -296,6 +296,12 @@ function module_enable($module_list) { node_access_needs_rebuild(TRUE); } } + + if (!empty($invoke_modules)) { + // Invoke the hook_module_enable after all the modules have been + // enabled. + module_invoke_all('modules_enabled', $invoke_modules); + } } /** @@ -321,6 +327,9 @@ function module_disable($module_list) { } if (!empty($invoke_modules)) { + // Invoke hook_module_disable before disabling modules, + // so we can still call module hooks to get information. + module_invoke_all('modules_disabled', $invoke_modules); // Refresh the module list to exclude the disabled modules. module_list(TRUE, FALSE); // Force to regenerate the stored list of hook implementations. Index: modules/simpletest/tests/system_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/system_test.module,v retrieving revision 1.2 diff -u -p -r1.2 system_test.module --- modules/simpletest/tests/system_test.module 8 Sep 2008 20:49:47 -0000 1.2 +++ modules/simpletest/tests/system_test.module 23 Sep 2008 20:31:19 -0000 @@ -84,3 +84,39 @@ function system_test_redirect_invalid_sc function system_test_destination() { return 'The destination: ' . drupal_get_destination(); } + +/** + * Implementation of hook_modules_installed(). + */ +function system_test_modules_installed($modules) { + if (in_array('aggregator', $modules)) { + drupal_set_message(t('hook_modules_installed fired for aggregator')); + } +} + +/** + * Implementation of hook_modules_enabled(). + */ +function system_test_modules_enabled($modules) { + if (in_array('aggregator', $modules)) { + drupal_set_message(t('hook_modules_enabled fired for aggregator')); + } +} + +/** + * Implementation of hook_modules_disabled(). + */ +function system_test_modules_disabled($modules) { + if (in_array('aggregator', $modules)) { + drupal_set_message(t('hook_modules_disabled fired for aggregator')); + } +} + +/** + * Implementation of hook_modules_uninstalled(). + */ +function system_test_modules_uninstalled($modules) { + if (in_array('aggregator', $modules)) { + drupal_set_message(t('hook_modules_uninstalled fired for aggregator')); + } +} Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.90 diff -u -p -r1.90 system.admin.inc --- modules/system/system.admin.inc 20 Sep 2008 20:22:24 -0000 1.90 +++ modules/system/system.admin.inc 23 Sep 2008 20:31:55 -0000 @@ -1091,9 +1091,8 @@ function system_modules_uninstall_submit if (!empty($form['#confirmed'])) { // Call the uninstall routine for each selected module. - foreach (array_filter($form_state['values']['uninstall']) as $module => $value) { - drupal_uninstall_module($module); - } + $modules = array_keys($form_state['values']['uninstall']); + drupal_uninstall_modules($modules); drupal_set_message(t('The selected modules have been uninstalled.')); unset($form_state['storage']); Index: modules/system/system.test =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.test,v retrieving revision 1.12 diff -u -p -r1.12 system.test --- modules/system/system.test 15 Sep 2008 20:48:09 -0000 1.12 +++ modules/system/system.test 23 Sep 2008 20:32:28 -0000 @@ -19,7 +19,7 @@ class EnableDisableCoreTestCase extends * Implementation of setUp(). */ function setUp() { - parent::setUp(); + parent::setUp('system_test'); $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration')); $this->drupalLogin($this->admin_user); @@ -39,6 +39,8 @@ class EnableDisableCoreTestCase extends $this->drupalPost('admin/build/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.')); + $this->assertText(t('hook_modules_installed fired for aggregator'), t('hook_modules_installed fired.')); + $this->assertText(t('hook_modules_enabled fired for aggregator'), t('hook_modules_enabled fired.')); $this->assertModules(array('aggregator'), TRUE); $this->assertTableCount('aggregator', TRUE); @@ -48,6 +50,7 @@ class EnableDisableCoreTestCase extends $this->drupalPost('admin/build/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.')); + $this->assertText(t('hook_modules_disabled fired for aggregator'), t('hook_modules_disabled fired.')); $this->assertModules(array('aggregator'), FALSE); $this->assertTableCount('aggregator', TRUE); @@ -58,6 +61,7 @@ class EnableDisableCoreTestCase extends $this->drupalPost(NULL, NULL, t('Uninstall')); $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.')); + $this->assertText(t('hook_modules_uninstalled fired for aggregator'), t('hook_modules_uninstalled fired.')); $this->assertModules(array('aggregator'), FALSE); $this->assertTableCount('aggregator', FALSE); }