Problem/Motivation
The method ModuleHandler::addModule() allows to add a module, and then ModuleHandler::add() attempts to add hook implementations for that module.
The methods were deprecated in #3481778: Deprecate functions using ModuleHandler::add(), and will be removed in Drupal 12.
We can assume that currently these method are rarely used, but their usage is still possible.
We already understand some limitations:
- Only procedural implementations are added.
- The resulting combined list of implementations is not properly ordered.
However, there is a bigger problem:
Calling ->add() removes existing implementations, and also prevents regular implementations from being added later.
Also, when ->resetImplementations() is called, the new implementations are lost.
This is much worse than simply not adding any new implementations.
Steps to reproduce
We can produce a KernelTest with code like this:
$module_handler = \Drupal::service(ModuleHandlerInterface::class);
// Assume that modules 'module_a' and 'module_b' are currently installed.
// Assume that implementations of test_hook return the respective module names.
$this->assertSame(['module_a', 'module_b'], $module_handler->invokeAll('test_hook'));
$module_handler->addModule('module_c');
$this->assertSame(['module_c'], $module_handler->invokeAll('test_hook')); // ouch!!!
$module_handler->resetImplementations();
$this->assertSame(['module_a', 'module_b'], $module_handler->invokeAll('test_hook')); // Implementation from module_c is forgotten.
One problem is the `->resetImplementations()` called within `->add()`.
We could remove this, but then it would still be problematic, if we call ->add() before ->invokeAll():
$module_handler = \Drupal::service(ModuleHandlerInterface::class);
// Assume that modules 'module_a' and 'module_b' are currently installed.
// Assume that implementations of test_hook return the respective module names.
$this->assertSame(['module_a', 'module_b'], $module_handler->invokeAll('test_hook'));
$module_handler->addModule('module_c');
// If we remove ->resetImplementations() from within ->add(), the old implementations are not lost.
$this->assertSame(['module_a', 'module_b', 'module_c'], $module_handler->invokeAll('test_hook')); // nice, I guess..
$module_handler->resetImplementations();
$this->assertSame(['module_a', 'module_b'], $module_handler->invokeAll('test_hook')); // Implementation from module_c is forgotten.
and
$module_handler = \Drupal::service(ModuleHandlerInterface::class);
// Assume that modules 'module_a' and 'module_b' are currently installed.
// Assume that implementations of test_hook return the respective module names.
// Assume that ->invokeAll('test_hook') was not called yet, so the list is not initialized.
$module_handler->addModule('module_c');
$this->assertSame(['module_c'], $module_handler->invokeAll('test_hook')); // ouch!!!
$module_handler->resetImplementations();
// Now the list can be properly initialized.
$this->assertSame(['module_a', 'module_b'], $module_handler->invokeAll('test_hook'));
Proposed resolution
Remove module add chain of methods and just empty them.
Remaining tasks
Review
User interface changes
N/A
Introduced terminology
N/A
API changes
Technically - I can add a CR for this.
Data model changes
N/A
Release notes snippet
N/A
Issue fork drupal-3528899
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
donquixote commentedComment #4
nicxvan commentedI really don't think people are using this.
It was a helper for Drupal install and updating and wasn't even working there for ages.
We can track it though.
Unless someone pops up though with a valid use case this is already deprecated. I'm not sure it's worth the effort to change.
Comment #5
nicxvan commentedIn fact I'm considering marking this postponed maintainer needs more info on an example of someone actually using this.
Comment #6
donquixote commentedMy main concern here is whenever we refactor this, e.g. in #3519561: Introduce ImplementationList objects per hook, to simplify ModuleHandler, we are replicating severely broken functionality.
Comment #7
nicxvan commentedJust to clarify you mean replicating broken functionality only within the add method right?
Comment #8
donquixote commentedyes.
Comment #9
donquixote commentedIt was working before the OOP hooks via EventDispatcher. So in 11.0.
Normally "deprecated" code still works as advertised or as expected, you should stop using it to prepare for the next major version.
Comment #10
nicxvan commentedPostponing until we have someone impacted by this.
Contrib projects that use this method would be most helpful, but I've not been able to find any contrib using it.
Feel free to set back to active if you find contrib using it and we can take another look.
Comment #11
nicxvan commentedI searched http://codcontrib.hank.vps-private.net/search?text=Drupal%3A%3Aservice%2...
And the other common ways this could be called and all returned 0 usages.
Comment #15
nicxvan commentedComment #16
catchI think we are probably OK to make these a no-op in Drupal 11.3 with an updated deprecation message if we're confident they're not being called in contrib, which it sounds like we are. I can't see any runtime use case for ever calling them so the most likely case would be a very custom installer or some test code maybe, if at all.
Comment #17
nicxvan commentedI have done another careful search and I found one module using it in a test.
I think it was created after this issue, I've opened an issue in that module to update it: #3549416: Update call to addModule
There is no release and no sites using it yet.
Do we need a CR?
Comment #18
smustgrave commentedSince this seemed to get sign off from @catch in #16 going to mark. Don't think we need a new CR but maybe update https://www.drupal.org/node/3491200 ?
Comment #19
nicxvan commentedI created a tentative CR and we can link the old one to the new one once this gets in.
Comment #20
nicxvan commentedAdding related issue that can be closed when this lands.
Comment #21
nicxvan commentedLet's postpone this on the separate hooks issue since that is now rtbc and far more important.
That will also require a reroll here.
Comment #22
donquixote commentedActually I would like this to go in asap, I don't see a big conflict with the other issue.
Comment #23
donquixote commentedThe other one will be super easy to rebase if this gets in first.
Comment #24
nicxvan commentedThe reverse is also true, and the other one has a few other issues dependent on it so I really think this should be postponed on that one.
I'm trying to remove roadblocks for the other one and forcing a rebase for this is a roadblock.
Comment #25
catchNeeds a rebase :)
Comment #29
nicxvan commentedThis is ready for review again.
Comment #30
berdirNew MR as the code has changed a lot. This just removes the code and I think still looks good. I haven't carefully reviewed the issues but it's almost never used and was already RTBC, with agreement on the direction, so...
Comment #33
catchCommitted/pushed to 11.x and cherry-picked to 11.3.x, thanks!