Updated: Comment #321
Suggested commit message: "Issue #2003966 by fubhy, swentel, alexpott, ParisLiakos, bojanz, aspilicious, beejeebus, steinmb: Fixed Disabled modules are broken beyond repair so the 'disable' functionality needs to be removed."
- Disabled modules cause data to be lost or get stale/unmaintained.
- Data of disabled modules cannot be staged.
- References from or to data in disabled modules are broken.
- Reliably removing data on uninstall is impossible (see ).
Drupal has two kinds of dependencies between modules:
1. Explicit, hard dependencies, as defined in dependencies - module A depends on module C.
2. Soft, conditional dependencies, as a result of references to things provided by module A in configuration owned by module B (possibly provided as a default by module C).
The second kind of dependency is the one which has caused most of the bugs with disabled modules.
Module A provides a field type plugin.
Module B (field module) references this field type plugin in a field/field instance configuration entity.
Module C provides an entity type and bundle.
Module B references the entity type and bundle in the same field plugin.
Module B does not have an explicit dependency on module A or C, but the configuration that it owns does.
Some modules like Views are able to handle these cases from the perspective of 'broken handlers'.
However modules dealing with user content (i.e. entity/field but also hard-coded references such as comment_node_statistics) are unable to guarantee data integrity. The modules that are still enabled may need to act on either their configuration entities or user data that is based on the configuration entity, but are unable to because the plugin/entity type is unavailable. When the plugin/entity type because available again, things may have moved on.
This can result in anything from php notices due to 'missing' data, to fatal errors where things have moved on significantly i.e. a module referencing serial IDs from another module that is disabled, uninstalled then reinstalled could end up referencing different entities altogether without having any way of knowing this.
At the moment modules try to deal with this in myriad different ways, from the Views concept of 'broken handlers', to field_info_system_alter() attempting to convert soft dependencies to hard dependencies dynamically.
(postponed on this issue) is necessary to resolve the situation for uninstalled modules.
David Rothstein has (rightly) pointed out that the same approach incan also be applied to disabled modules too, if we additionally enforce modules are uninstalled in one step (i.e. remove the ability to go from disabled -> uninstalled). However, given a critical issue to restore the disabled modules UI in a more limited way, this ends up at the same end point, just via different routes.
There are various examples given in the issue, as well as many other bugs which are less fundamental, but still numerous, hard to solve and frequent due to the inherent instability/limbo state of disabled modules, and a lack of clarity in terms of what it means.
- Field types disappear; all field values get stale.
- Entity types disappear; all references are unresolvable, data is lost.
- Plugin types disappear, and along with it, all plugin IDs; all unresolvable plugin references get orphaned.
- Disabled modules worked well in a time when every module was an atomic, isolated isle, mostly doing its own thing, with its own data, and its own functionality. Today, the world of Drupal modules is too abstract, too modular, and too integrated, in order for that concept to work.
Today, a "disabled module" means two totally different things:
- The module's functionality disappears from the user interface.
- The module's functionality disappears from the API (the code isn't loaded, its hook implementations aren't invoked, etc).
By merging 1) and 2) in the concept of disabled modules, instead of just doing 1), we've created a high number of critical/major bugs in the past couple of years. Some of those include:
Solution in #317 and API changes
- Completely removes the concept of disabled modules.
- system.module.disabled config is removed.
module_enable()is deprecated and now does an install.
module_disable()is removed as it does not make sense to change this to the destructive operation of uninstalling modules.
- All usages of
module_disable()are removed from core.
module_uninstall()is deprecated but core usages are left to be converted in a followup (this is less confusing than
- The following hooks are removed:
- The following hooks are added:
The change from invoking hook_modules_preinstall() with a list of modules to invoking hook_module_preinstall() with single module is so that we can guarantee the environment that will be running when the preinstall action is fired before installing a particular module. For example if both taxonomy and forum are being installed this change means that you now know that the taxonomy will be installed when the hook fires for the forum module - which is a good thing because taxonomy is a dependency for forum.
In order to explore the ability to disable modules the contrib module https://drupal.org/project/disable_modules has been created
Updating contrib code
module_disable(array('mymodule'))should be removed.
hook_enable()functionality should be moved to
hook_modules_enabled($modules)functionality should be moved to
hook_disable()functionality should be moved to
hook_modules_disabled($modules)functionality should be moved to
hook_module_preuninstall($module)(note per module not a list)
hook_modules_preenable($modules)functionality should be moved to
hook_module_preinstall($module)(note per module not a list)
hook_modules_preinstall($modules)functionality should be moved to
hook_module_preinstall($module)(note per module not a list)
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch disabled-fix_0.patch. Unable to apply patch. See the log in the details link for more information.
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch disabled-fix.patch. Unable to apply patch. See the log in the details link for more information.
PASSED: [[SimpleTest]]: [MySQL] 58,266 pass(es).
PASSED: [[SimpleTest]]: [MySQL] 58,437 pass(es).
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch 1199946-372_0.patch. Unable to apply patch. See the log in the details link for more information.