Skip to content

feat: add ReplaceUserRolePermissionFunctionsRector for Drupal 11.5 (#425) - #426

Open
bbrala wants to merge 1 commit into
mainfrom
feat/user-role-permission-functions-2025089
Open

bbrala wants to merge 1 commit into
mainfrom
feat/user-role-permission-functions-2025089

Conversation

@bbrala

@bbrala bbrala commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Closes #425.

Adds ReplaceUserRolePermissionFunctionsRector, rewriting the three procedural user role permission helpers deprecated in drupal:11.5.0 and removed in drupal:13.0.0:

  • user_role_grant_permissions()RoleInterface::grantPermissions()
  • user_role_revoke_permissions()RoleInterface::revokePermissions()
  • user_role_change_permissions()RoleInterface::changePermissions()

Issue: https://www.drupal.org/i/2025089 · Change record: https://www.drupal.org/node/3348027

// Before
user_role_grant_permissions('anonymous', ['access content']);

// After
\Drupal\user\Entity\Role::loadOverrideFree('anonymous')
  ?->grantPermissions(['access content'])
  ?->save();

The role is loaded with the static Role::loadOverrideFree() and chained with nullsafe operators — the pattern core itself adopted in media_install() and node_install(). Calls using named arguments, argument unpacking, or an argument count the deprecated functions never had are left untouched.

Why BC-wrapped

Both the static ConfigEntityBase::loadOverrideFree() and the three RoleInterface methods arrive with this deprecation (core e1f2b85d319, https://www.drupal.org/i/3620216), so the rewritten chain would fatal with "Call to undefined method" on Drupal < 11.5. Only the pre-existing storage method ConfigEntityStorage::loadOverrideFree() predates it, which is a different call shape — verified with git grep against e1f2b85d319~1.

First Drupal 11.5 rule

There was no 11.5 set yet, so this also adds config/drupal-11/drupal-11.5-deprecations.php and registers DRUPAL_115 in:

  • src/Set/Drupal11SetList.php
  • config/drupal-11/drupal-11-all-deprecations.php
  • src/Set/DrupalSetProvider.php (composer-based selection — without this a site on drupal/core ^11.5 would never load the rule)

DrupalSetProviderTest gains a data row pinning 11.5 cumulative matching.

Reviewer note: the rule is dormant until core branches 11.5

Core's 11.x branch still reports VERSION = '11.4-dev' while already carrying the 11.5.0 deprecation — the constant is bumped at release-branch time. installedDrupalVersion() normalises that to 11.4.0, so the 11.5.0 gate correctly declines to fire. Running this against today's 11.x-dev yields zero diffs by design. It activates once core reports 11.5.

Validation

Live-tested against D11-compatible contrib with the version overridden to 11.5.018 files / 57 call sites rewritten, all passing php -l, none missed:

Module Installs Files
commerce 12,633 6
search_api 147,269 3
webform 120,205 2
sitewide_alert 6,635 2
captcha 131,831 1
matomo 19,558 1
pwa 1,784 1
legal 1,388 1
profile 35,554 1

Shapes covered: string literal and variable role IDs, AccountInterface::ANONYMOUS_ROLE / RoleInterface::ANONYMOUS_ID constants, chained $role->id(), multi-line permission arrays, and fully-qualified calls (\user_role_grant_permissions(, as matomo writes it) — that last one came out of reading real contrib and is now pinned by a fixture.

Also verified: idempotent under a two-pass CLI run with importNames enabled (the isInBackwardsCompatibleCall() guard stops the rule re-firing on the call parked in the deprecatedCallable slot).

PHPStan messages captured against drupal/core:11.x-dev and added to docs/coverage-registry.php.

Checks

  • vendor/bin/phpunit — 702 tests, 967 assertions, green
  • composer phpstan — no errors
  • composer fix-style — no changes

user_role_grant_permissions(), user_role_revoke_permissions() and
user_role_change_permissions() are deprecated in drupal:11.5.0 and removed in
drupal:13.0.0 (https://www.drupal.org/i/2025089, change record
https://www.drupal.org/node/3348027). Each call is rewritten to the matching
\Drupal\user\RoleInterface method on a role loaded with
\Drupal\user\Entity\Role::loadOverrideFree(), the nullsafe chain core itself
adopted in media_install() and node_install().

BC-wrapped: the static Role::loadOverrideFree() and the three RoleInterface
methods all arrive with the deprecation itself (core e1f2b85d319,
https://www.drupal.org/i/3620216), so the rewritten chain would fatal with
"Call to undefined method" on Drupal < 11.5.

Calls using named arguments, argument unpacking, or an argument count the
deprecated functions never had are left untouched.

First Drupal 11.5 rule, so it also adds
config/drupal-11/drupal-11.5-deprecations.php and registers DRUPAL_115 in
Drupal11SetList, drupal-11-all-deprecations.php and the composer-based
DrupalSetProvider.

The rule stays dormant until core branches 11.5: core's 11.x branch still
reports VERSION = '11.4-dev' while already carrying the deprecation, so the
version gate correctly declines to fire until then.

Tested: commerce (6 files changed), search_api (3), webform (2),
sitewide_alert (2), captcha (1), matomo (1), pwa (1), legal (1), profile (1)
— 18 files, 57 call sites rewritten, all passing php -l
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add rector for deprecated user_role_grant/revoke/change_permissions() (Drupal 11.5)

1 participant