Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
This is a small patch inspired by bjaspan's call for better developer experience.
The patch adds a small function module_permission_uninstall($module)
that is automatically invoked when a module is uninstalled. This has the benefit of automatically cleaning the {role_permission} table when modules are uninstalled.
Comment | File | Size | Author |
---|---|---|---|
#79 | uninstalled.patch | 949 bytes | catch |
#76 | notice.patch | 1010 bytes | catch |
#67 | user_modules_uninstalled_2.patch | 4.35 KB | agentrickard |
#66 | user_modules_uninstalled.patch | 4.36 KB | catch |
#64 | user_modules_uninstalled.patch | 4.39 KB | catch |
Comments
Comment #1
agentrickardTODO: Convert to the DBTNG format for the delete.
Comment #2
Dave ReidShould this also be expanded to deleting node types, blocks, and actions (things that are automatically defined by the module and not the module.install?)
Comment #3
agentrickardPossibly, but not in this patch. Generally, things like node types are handled by the module's own implementation of hook_uninstall().
However, since permissions are handled through a universal hook_perm(), it seems natural to do this automatically instead of forcing developers to delete them with extra code.
Comment #4
Dave ReidActually since node types are handled through hook_node_info, it would be smart to uninstall those automatically. Same with hook_block().
Comment #5
moshe weitzman CreditAttribution: moshe weitzman commentedGood idea about perms (and blocks) ... We should only issue one delete query with an IN clause. For example, DELETE WHERE perm IN ('administer foo', 'manage foo') ...
Comment #6
agentrickardArgh! Why is there no Drupal function for creating an IN query?!?
As to node types and blocks -- separate patches for those, please. Unless we want to turn this into a function that checks all the "known" uninstall items.
Comment #7
moshe weitzman CreditAttribution: moshe weitzman commentedah, but now we do. from one of your favorite functions:
Comment #8
agentrickardOK, I take that last rant back a bit. The new db_query accepts arrays. Nifty.
New patch attached.
Let's open other issues for blocks and such.
Comment #9
agentrickard@Dave Reid
See #306151: Automatically install/uninstall schema
Comment #10
agentrickard@moshe
Cool! Here's a new version using DBTNG!
Comment #11
Dave ReidHah! I actually submitted an issue for a new hook that would help with exactly that: #253569: DX: Add hook_modules to act on other module status changes. Would need to get that into core first.
Comment #12
agentrickardI am perfectly ok with rolling this patch into #306151: Automatically install/uninstall schema after #253569: DX: Add hook_modules to act on other module status changes lands.
In that case, this patch would go into user.module as user_module() with $op uninstall.
Comment #13
Anonymous (not verified) CreditAttribution: Anonymous commentedsubscribe
Comment #14
agentrickardNew function would be:
Comment #15
drewish CreditAttribution: drewish commentedi think this should be postponed pending #253569: DX: Add hook_modules to act on other module status changes
Comment #16
agentrickardYes. It should. The function in #14 is dependent on that patch.
Setting to CNW.
Comment #17
Dave ReidAlright! We can finally get this in now! Although we should probably get some tests written for this.
Comment #18
moshe weitzman CreditAttribution: moshe weitzman commentedThat issues a delete query for each module. We can do a single delete for all modules by moving the query below the foreach().
Comment #19
agentrickardDave - see the patch in #10 for the syntax that Moshe refers to. DBTNG lets us pass arrays of deletes.
The drupal_load() is not needed either, since those modules get loaded by
drupal_uninstall_modules()
during the same page load cycle. So the functions are all still in memory.Comment #20
moshe weitzman CreditAttribution: moshe weitzman commentedNope, #10 isnt it. That does a query per module as well. You can do this with one big IN clause.
Comment #21
agentrickardMoshe is right. :-(
Comment #22
drewish CreditAttribution: drewish commentedwas this more what you had in mind? we should probably add a test to ensure this works as advertised.
Comment #23
agentrickardThe drupal_load() there is redundant. This hook is invoked at the end of http://api.drupal.org/api/function/drupal_uninstall_modules/7
Comment #24
Dave ReidActually, we don't need to have the drupal_load in drupal_uninstall modules anymore. That was only used for the menu paths uninstalling, but that would depend on #320303: Remove module menus on uninstall.
Comment #25
drewish CreditAttribution: drewish commentedwell either of you could have re-rolled it without that ;) so tag now you guys get to write the tests ;)
Comment #26
Dave ReidSorry I've been only on to just check a few update statuses. I'm actually getting the hang at writing tests, so I'll get started on that.
But I have a question I wanted to ask everyone about these newtests for hook_modules_uninstalled: should they be done by the respective module or should we create/use a simpletest dummy module that implements one block, filter, permission, etc and be able to combine all these new tests in one test, much like the module list test in system.test. Ideas or thoughts?
Comment #27
agentrickardWell, I think we want to keep the drupal_load() in drupal_uninstall, otherwise, we have to fire it every time we write a hook_modules_uninstalled().
No opinion about testing.
Comment #28
moshe weitzman CreditAttribution: moshe weitzman commentedProgress, anyone?
Comment #30
Dave ReidRe-rolled. Any suggestions for which module could host the appropriate test files? Build off of the module enable/disable test?
Comment #31
drewish CreditAttribution: drewish commentedi think we could add a module.test and module_test.module to handle this. once there's an obvious place for it i think we'd be well served to add have some unit tests for module.inc.
Comment #32
dawehneri added tests to this patch, not sure wether this is the right way to check it
Comment #33
drewish CreditAttribution: drewish commentedI think the test could be a little simpler:
Comment #34
drewish CreditAttribution: drewish commentedAlso all the comments should be "Proper sentences."
Comment #35
dawehnerthx for the review!
here is a better patch, i hope :)
Comment #36
drewish CreditAttribution: drewish commentedshould be:
The ModuleUninstallTest class needs a PHPDoc block.
Other than that this is looking good.
Comment #37
dawehnerthx for taking the time to review
so there is another patch
Comment #38
drewish CreditAttribution: drewish commentedAny reason this testcase isn't in ModuleUnitTest?
Comment #39
Dave ReidProbably because the ModuleUnitTest has a different setUp requirement than the uninstall test case. Will do further review shortly.
Comment #40
dawehnernot really, i thought because of user module, but this is silly
because user module is loaded every time
just wonders whether the function should be under or above assertModuleList()
Comment #41
dawehnerdamn this cannot work!
Comment #42
dawehnersry for the 3 posts
so this time with a setup function
Comment #43
drewish CreditAttribution: drewish commenteddidn't test it but visually it's fine by me.
Comment #44
dawehnersry but this cannot work
$this>assertModuleList()
gets all active modules, and check with expected modules, (but there are path module_test and user, and not just path)so we have to add module_test and user to this expected values or we have to add another testclass
Comment #45
drewish CreditAttribution: drewish commentedthen modify assertModuleList() to add module_test and user in there.
Comment #46
Dave ReidYou don't need to call setUp with the user module. It is automatically installed since it's a required core module.
Comment #47
Dave ReidIMHO I think this should be in a separate test class, since eventually we're going to be adding more uninstall tests. The current ModuleUnitTest tests "low-level API functions" which is not what we're testing. We should have a new "class ModuleUninstallUnitTest" to fit the core test class name standards.
Comment #48
dawehneri tryed to solve this, but i couldn't do it, anyone else know know how to solve it?
at least this patch reduces the fails to 4
Comment #49
dawehner#47 sounds logical for me
so i took #37 and fixed a code style problem at the beginning of the file and added a better comment
Comment #50
Dave ReidComment #52
agentrickardAttached is an updated patch, but the tests all fail because there is no 'module_test.module' file.
Comment #53
dawehnerarg, i created this module before, but i didn't added it to the patch file :(
Comment #54
agentrickardExcellent. Having the module_test.module will help with all the related DX patches, too, since we can dump dummy hooks there.
Comment #55
dawehnerso what other things could be removed automatically
sry for not checking them, whether they get removed
Comment #56
agentrickardDave Reid has a list over at #306151: Automatically install/uninstall schema
Comment #57
dawehnerwhats the best way to handle the waiting to get something like this commited?
should i wait to create the other testspatches untill this is commited?
Comment #58
agentrickardOr note the dependency in the other issues, which may get more attention on this one.
Comment #59
Dave ReidPatch review:
class ModuleUninstallTest extends DrupalWebTestCase
Please rename to ModuleUninstallUnitTest as per the testing naming standards.
parent::setUp('module_test', 'user');
Please exclude 'user' since it is automatically installed (it's a required core module).
We need to test to make sure the permissions are actually found in the {role_permission} table so that we know for sure the uninstall deletion works. Something like:
The module name should be "Module test"
The user_modules_uninstalled() should have a call to drupal_load('module', $module) because the functions in module_test.module will not be loaded into the function registry during uninstall since the modules have been disabled.
Comment #60
catchThis is now a critical bug since user_modules_installed() automatically adds permissions to the admin role when modules are installed, but doesn't remove them - leading to PDO errors when you uninstall then reinstall a module.
Attached patch fixes bugs in the most recent one here, and adds additional tests by pp from #503554: user_modules_uninstalled() is missing
Comment #62
catchCan't reproduce locally either running in the UI or via the command line. Trying once more.
Comment #64
catchForgot the -N flag when creating the patch, whoops.
Comment #65
agentrickardYou do not need to run drupal_load() on each module. drupal_uninstall_modules() does this for you before firing the hook.
http://api.drupal.org/api/function/drupal_uninstall_modules/7
Comment #66
catchdoh, fixed.
Comment #67
agentrickardSorry. Typos:
These should be fixed in the attached.
I am not sure what the aggregator bit is doing in the test function. Is that left over from another patch? If it's needed here, just say so.
Comment #68
catchThe aggregator test hunk is from another issue which was a straight bug report, but this issue is the proper fix for it. It tests that you can safely uninstall and reinstall a module (at the moment it throws a lot of PHP warnings due to user_modules_installed() trying to insert permissions for the admin role which were never removed.
Comment #69
agentrickardOK then!
Comment #70
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD. Thanks all!
I'd like to see us rename all instances of 'perm' to 'permission' so marking this 'code needs work'.
Comment #71
catchThis issue is already pretty long - I've opened #506976: Stop abbreviating permissions to perm so we can continue there.
Also added a short note about this to the 6/7 update documentation.
Comment #72
asimmonds CreditAttribution: asimmonds commentedThe committed patch results in a couple of notices when you uninstall a module that doesn't implement hook_perm eg profile.module.
Comment #73
catchack, untested patch.
Comment #74
catchIs there a core module with no hook_perm() or maybe one of the test ones? We could add that to the uninstall test.
Comment #76
catchAnd the path that was supposed to come with #53.
Comment #78
agentrickardPatch needs to update to hook_permission()
Comment #79
catchComment #80
moshe weitzman CreditAttribution: moshe weitzman commentedi think the code would be a tiny bit briefer if you use foreach (module_implements('permission') as $module). you won't loop over unnecessary modules and you can omit the drupal_function_exists().
Comment #81
catchWe don't want to remove permissions for every module which implements hook_permission(), only those ones which are being uninstalled and given as the parameter to hook_modules_uninstalled() - so module_implements() isn't an option here.
There's other ways to check if we get any permissions from a module before running array_keys() on it (that original hunk of code wasn't mine - I just re-rolled it into the patch which was committed), but they're all fairly equally verbose.
Comment #82
moshe weitzman CreditAttribution: moshe weitzman commentedah right. makes sense now.
Comment #83
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD. Thanks.