Problem/Motivation
The contributed module ecosystem has had to craft ways to provide backward compatibility between minor and major versions of Drupal core.
- Minor versions: silence runtime deprecations triggered while supporting the current major version's minor versions with security coverage.
- Major versions: prevent calling deprecated code that was removed while bridging support with the latest minor version of the last major version (9.5 && 10.0.)
It often looks like this:
if (version_compare(\Drupal::VERSION, '9.4', '>=')) {
// Do the new way introduced in 9.4, and supported in 9.5 and 10.0.
}
else {
// @phpstan-ignore-next-line
// Call the deprecated code for 9.2 and 9.3.
}
This is painful to copy around. It can be simplified if Drupal provided a utility class method or function that allowed invoking the correct code based on the provided version. I envision the signature being the following:
string $version
: The value to pass toversion_compare(\Drupal::VERSION, $version, '>=')
callable $current
: A callable to be invoked ifversion_compare
istrue
.callable $deprecated
: A callable to be invoked ifversion_compare
isfalse
This would also return any values just like \Drupal\Core\Render\RendererInterface::executeInRenderContext()
.
PHPStan's deprecation rule package can now define custom deprecation scopes (see https://github.com/phpstan/phpstan-deprecation-rules/pull/99.) The phpstan-drupal package can then consider this as a deprecated scope, removing the need for @phpstan-ignore-next-line
throughout backward compatibility layer code.
Some of my relevant blog posts on this topic:
- https://mglaman.dev/blog/adding-backward-compatibility-rector-rules
- https://mglaman.dev/blog/drupal-module-semantic-versioning-drupal-core-s...
Proposed resolution
Create the method backwardsCompatibleCall
on the \Drupal
global class.
Here is an example:
$roles = \Drupal::backwardsCompatibleCall(
version: '10.1',
current: fn () => Role::loadMultiple(),
deprecated: fn () => user_roles(),
);
Ideally this would be added to a version of Drupal 10 early enough that the Drupal 11 readiness work can leverage it. That means modules choosing to do so would need to drop previous minor versions of Drupal 10. So if this landed in 10.2 and 10.4 would be our last minor before Drupal 11, modules could safely support ^10.2.0 || ^11
and use this.
Remaining tasks
- Decide if this is a good idea
- Bikeshed words
API changes
Introduces a new backward compatibility API.