Problem/Motivation
With Drupal 10, the handling of permissions became more strict when it comes to non-existent permissions. Unfortunately, the dynamic creation and removal of permissions provided by block_permissions currently does not work well with this change when it comes to the deinstallation of another module and when a permission provided for the removed module is in use. In this case the system is somewhat locked to an invalid state:
- Trying to change any permission creates the following exception:
"RuntimeException: Adding non-existent permissions to a role is not allowed. The incorrect permissions are "administer blocks provided by <removed_module>". in Drupal\user\Entity\Role->calculateDependencies() (line 207 of core/modules/user/src/Entity/Role.php)."
...
- The permission itself can no longer be removed from the role as, due to its dynamic creation and removal, it does not exist.
Steps to reproduce
I will use the module "Webform" and the role "Manager" as an example. The problem should ocure with every module and, except of the admin, with every role.
- Install the module "Webform"
- In /admin/people/permissions: Add the permission "administer blocks provided by webform" to the role Manager
- Uninstall the module "Webform"
- Again in /admin/people/permissions: Change any permission and try to save the change.
In this case, the exception following exception should become visible:
"RuntimeException: Adding non-existent permissions to a role is not allowed. The incorrect permissions are "administer blocks provided by webform". in Drupal\user\Entity\Role->calculateDependencies() (line 207 of core/modules/user/src/Entity/Role.php)."
...
Proposed resolution
When the module creates permissions, it should declare the dependencies of those permissions. See the change record
Permissions can define dependencies β
.
Original proposed resolution
I am not sure about the best timing and place to do this as this would have to react on the deinstallation of other modules, but would alter existing permissions (and maybe this is not wanted)
I was thinking about something like this:
/**
* Implements hook_modules_uninstalled().
*/
function block_permissions_modules_uninstalled($modules, $is_syncing) {
$roles = Role::loadMultiple();
foreach ($modules as $module) {
foreach ($roles as $role) {
if ($role->hasPermission('administer blocks provided by ' . $module)) {
$role->revokePermission('administer blocks provided by ' . $module);
$role->save();
}
}
}
}