This issue grew out of #306027: user_modules_uninistalled() is missing. Looking at drupal_uninstall_module(), it seems to me that the function is very non-Drupal. It calls a module-specific hook and then does some menu cleanup.

However, we also need to do permission, block, and other types of automated cleanup. Now we could force the developer to do these in hook_uninstall(), but it seems a better solution is a hook that lets modules act on their 'child' hooks.

That is, the current logic for menu cleanup should go into a menu.inc function.

Proposed hook would be hook_uninstall_module(), whith $module a string as parameter.

Some uses:

-- user.module user_uninstall_module($module) to remove permissions set by the module.
-- menu.inc menu_uninstall_module($module) to remove menu items set by the module.
-- block.module block_uninstall_module($module) to remove blocks set by the module.
-- node.module node_uninstall_module($module) to remove node types items created by the module.

This could also apply to trigger, filter, and other core modules. Making it a hook would also let contibuted modules (like Views) perform cleanups.

We could also use a similar function that fires a hook on module enable/disable, so that modules can react to changes in the module list.

Comments

dave reid’s picture

Assigned: Unassigned » dave reid

Actually this would be a perfect use for #253569: DX: Add hook_modules to act on other module status changes! Yay! Working on patch...

dave reid’s picture

StatusFileSize
new2.75 KB

Here's just some functions that would show what would be changed. Not a patch.

agentrickard’s picture

I support hook_module(). Then we can use this issue for implementing the above list of implementations.

Anonymous’s picture

+1 - subscribe

moshe weitzman’s picture

That pseudo patch is quite nice. Anyone available to refine and re-submit?

dave reid’s picture

dave reid’s picture

babbage’s picture

Subscribing.

dave reid’s picture

agentrickard’s picture

Status: Active » Needs review
StatusFileSize
new2.19 KB

Here is a test patch to get this rolling.

It appears that we can simply call the schema hooks directly, which removes an unneeded module_load_install(), since the schema function calls that.

Tested by removing hook_install() from comment module and removing drupal_uninstall_schema() from comment_uninstall().

I think this is the right approach -- it lets us remove cruft and streamline DX.

Status: Needs review » Needs work

The last submitted patch failed testing.

babbage’s picture

Subscribing.

catch’s picture

Title: DX: Improve the module uninstall system » Automatically install/uninstall schema

Re-titling, interesting patch.

agentrickard’s picture

@catch

This was a DX movement that Dave Reid and I were workin on and we got sidetracked. The idea is simple:

Module authors should not need to declare their own schema (un)installs, since Drupal is smart enough to do that for them. In fact, there are a number of related tasks that can be automated.

agentrickard’s picture

StatusFileSize
new2.19 KB

Patch applies cleanly in dev. The problem is that it will break almost all tests, since we have to remove the duplicate install/uninstall calls.

damien tournoud’s picture

     // Uninstall the module.
-    module_load_install($module);
+    drupal_uninstall_schema($module);
     module_invoke($module, 'uninstall');

(1) why removing the module_load_install() call?
(2) I would rather see the schema installation happen *after* we called the uninstall hook.

agentrickard’s picture

1) Because drupal_uninstall_schema() calls module_load_install() already, so we don't need both. (It happens in http://api.drupal.org/api/function/drupal_get_schema_unprocessed/7)

2) This comment makes no sense. Installation after uninstallation? You mean reverse the order. Call the module's hook_uninstall() in case the module needs to act on its data?

     // Uninstall the module.
     module_load_install($module);
     module_invoke($module, 'uninstall');
     drupal_uninstall_schema($module);

In that case, we would need the module_load_install(). But are there use-cases for modules that act to cleanup after their own data?

moshe weitzman’s picture

Sure he meant "would rather see the schema uninstallation happen *after* we called the uninstall hook". I agree that this sounds safer. Some uninstall logic may depend on the state of the tables.

catch’s picture

The uninstall hook absolutely has to run while the tables are still there - if I need to call an API function for the uninstalled module to do clean up something in my module, the tables have to be there for that to work (say cleaning out vocabulary related tables when taxonomy module is uninstalled).

webchick’s picture

I would love to see this fixed before code freeze. It's always embarrassing explaining to people that they need to explicitly install/uninstall their tables.

agentrickard’s picture

@webchick

Does that mean you want to see a patch against all of core using the pattern defined in #17?

agentrickard’s picture

For the record, there is an instance in book.install that validates Damien's correction.

agentrickard’s picture

StatusFileSize
new23.77 KB

And here we go. For some reason, this patch breaks SimpleTest entirely, but I can't figure out why.

agentrickard’s picture

Status: Needs work » Needs review

Bumping to get some eyes on the testing problem.

Status: Needs review » Needs work

The last submitted patch failed testing.

agentrickard’s picture

Status: Needs work » Needs review
StatusFileSize
new25.2 KB

Bah. This fails because drupal_install_schema() -- used in system_install() -- doesn't update the schema version of a module, which makes no sense to me.

I account for that by wrapping db_create_table() in db_table_exists() check, which fixes the problem.

But the schema install functions are spread out all over the place. Some are in common.inc and some are in install.inc. I think they should all be centralized in database.inc, and the db_install_schema should update the {system} table.

But that is a different patch.

Status: Needs review » Needs work

The last submitted patch failed testing.

agentrickard’s picture

Status: Needs work » Needs review
StatusFileSize
new25.92 KB

This seems to work fine now. Let's see what testbot says!

Status: Needs review » Needs work

The last submitted patch failed testing.

agentrickard’s picture

This works, but testbot hates it. I have no idea how to make the bot happy.

agentrickard’s picture

Status: Needs work » Needs review
StatusFileSize
new25.92 KB

Found out why the tests fail, I think. Trying again.

Crell’s picture

Status: Needs review » Reviewed & tested by the community

About time we used the schema properly...

David_Rothstein’s picture

This patch would make it impossible to uninstall a whole bunch of modules via the Drupal user interface - since only modules which implement hook_uninstall() show up on the list.

I've leaving this RTBC because that can probably be fixed in a very simple followup, but it's critical that it be fixed if this patch goes in.

Crell’s picture

Should be easy to add. Just show any module with an uninstall hook OR a schema hook. Problem solved.

agentrickard’s picture

@David_Rothstein

Then why do all tests pass? Can you prove this? Happy to fix if you can provide an error.

David_Rothstein’s picture

StatusFileSize
new26.72 KB

Hm, it's a good question why there is no test that catches this. I checked, and we do have a test that uninstalls modules via the UI, but it uses the aggregator module when doing so, and that module still has a hook_uninstall() even after this patch, so that's why it doesn't catch it. I suppose we could change it to use a different module that would catch this case, but it would be somewhat fragile to rely on that anyway, so maybe not worth doing.

Anyway, as was said above, this is easy to fix. The attached patch is identical to the previous one, except for the addition of this:

Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.197
diff -u -p -r1.197 system.admin.inc
--- modules/system/system.admin.inc	26 Aug 2009 10:53:45 -0000	1.197
+++ modules/system/system.admin.inc	9 Sep 2009 03:56:17 -0000
@@ -1051,10 +1051,10 @@ function system_modules_uninstall($form_
     // Grab the module info
     $info = unserialize($module->info);
 
-    // Load the .install file, and check for an uninstall hook.
+    // Load the .install file, and check for an uninstall or schema hook.
     // If the hook exists, the module can be uninstalled.
     module_load_install($module->name);
-    if (module_hook($module->name, 'uninstall')) {
+    if (module_hook($module->name, 'uninstall') || module_hook($module->name, 'schema')) {
       $form['modules'][$module->name]['name'] = array('#markup' => $info['name'] ? $info['name'] : $module->name);
       $form['modules'][$module->name]['description'] = array('#markup' => t($info['description']));
       $options[$module->name] = '';

Pretty trivial, so still RTBC.

To see the difference between this patch and the previous one, try disabling the database logging module and then going to the uninstall page. The previous patch would not give you an option to uninstall the module via the UI (and therefore you'd be stuck with the watchdog table around forever), but this one does.

agentrickard’s picture

Excellent catch!

dries’s picture

Status: Reviewed & tested by the community » Needs work

Great little improvement. Committed this to CVS HEAD. This needs to be documented in the upgrade instructions so marking this as 'code needs work'. Set to 'fixed' after it has been properly documented. Thanks!

dropcube’s picture

Issue tags: +Needs documentation

Needs Documentation

agentrickard’s picture

Status: Needs work » Needs review
robloach’s picture

Status: Needs review » Fixed

Awesome to the max!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

deciphered’s picture

Status: Closed (fixed) » Active

I know this was marked as done quite some time ago, but I notice that with the latest dev release of Drupal 7 that if a module doesn't have hook_uninstall defined it will not show up in the uninstall list or uninstall the schema, which I distinctly see discussed in this issue.

Was it rolled back? Do I need to have hook_uninstall defined even when it has no contents?

Cheers,
Deciphered.

dave reid’s picture

Status: Active » Fixed

No, it should list any modules that have hook_uninstall *or* hook_schema.

deciphered’s picture

Status: Fixed » Closed (fixed)

Dave,

A module I was using definitely wasn't showing up in the uninstall list when it did have hook_schema defined but not hook_uninstall.

It does appear to be working now. I did update to todays dev release (from yesterdays) between the time of creating my previous post, so that could have been the cause.

Either way, it definitely wasn't showing up and is now, so I will re-close this unless I manage to uncover anymore information.

Cheers,
Deciphered.

geerlingguy’s picture

WhiplashInfo’s picture

Dubble Hhhhmmmm:

This isn't fixed:
http://drupal.org/node/1031120#comment-4863198

Just now I tryed to activate User Revisions as the core tell my that it exist. But that didn't worked. I was given a PDOException:
---------------------------
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'web25518_drup1.user_revision' doesn't exist: update user_revision set vid=0 where uid=0;; Array ( ) in user_revision_install() (line 165 of /home/web25518/domains/fmedk.se/public_html/d/sites/all/modules/user_revision/user_revision.install).
---------------------------
I use Core version 7.7

Thanks / Tomas