At MidCamp a few weeks ago, Martin Anderson-Clutz tapped me on the shoulder to check out a Smart Date issue for compatibility with Drupal 10.2. As of Drupal 10.2, ListItemBase::extractAllowedValues
takes an array as its first argument versus a string. The method used to explode a newline separated string into an array for its callers. I took a look at the issue. The change affected the parseValues
method in the SmartDateListItemBase
class. The parseValues
method takes the field's values and passes them to extractAllowedValues
, the method with a changed signature in Drupal 11.
The original method contained the following:
/**
* {@inheritdoc}
*/
public static function parseValues($values) {
// Use the ListItemBase parsing function, but don't allow generated keys.
$result = static::extractAllowedValues($values, 1);
return $result;
}
The fix was the following:
/**
* {@inheritdoc}
*/
public static function parseValues($values) {
// Use the ListItemBase parsing function, but don't allow generated keys.
$list = explode("\n", $values);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
$result = static::extractAllowedValues($list, 1);
return $result;
}
Everyone RTBC'd a patch that would break the module, and any further fixes for folks below 10.2 would force a new minor version of the module! That's not good. Luckily, Drupal now has utilities that make it easier than ever to write backward-compatible code.
I will walk through how I made the method work across multiple minor versions of Drupal core without triggering deprecation notices.
Keep Smart Date compatible with all versions of Drupal 10
The Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall
method allows handling backward-compatible code branches. This utility was added to Drupal 10.1.3, and Smart Date supports those few sites that are still on Drupal. While they should upgrade to Drupal 10, we don't have to drop support for 10.0.
First, we check if the DeprecationHelper
exists. If it doesn't, we know the code base is unaffected by the deprecation.
if (!class_exists(DeprecationHelper::class)) {
return static::extractAllowedValues($values, 1);
}
Then, we use DeprecationHelper::backwardsCompatibleCall
to support calling two different code branches, the deprecated and current version, using closures. The first arguments to backwardsCompatibleCall
allow determining whether the current version of Drupal is before or after the deprecation. The first callable is used if we're running a version after the deprecation; otherwise, the second one is.
return DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.2',
static function () use ($values) {
$list = explode("\n", $values);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
return static::extractAllowedValues($list, 1);
},
static fn () => self::extractAllowedValues($values, 1)
);
I took the proposed fix, which was correct, and placed it into the currentCallable
argument and the existing code for the deprecatedCallable
argument. Now, the maintainers of Smart Date can continue delivering bug fixes without leaving users behind, and users have a simple upgrade path without worrying about dropped minor version support of Drupal core.
You can find the full commit here: smart_date/-/commit/1dcd8f2beae45ceaa3e941c1819d6d1c0995dffb
Want more? Sign up for my weekly newsletter