Problem/Motivation
When we make changes to config entities/schema it requires the following:
1. A post_update hook that uses ConfigEntityUpdater to batch update all existing config entities of whatever type is being changed. This will update exported config for existing sites when core is updated to a new version.
2. A pre_save hook that does the same thing as 1 and also throws a deprecation message. This is for contrib modules, profiles, etc which have config in config/install (or test modules) so they know their exported config also needs to be updated.
The emerging pattern is to do the following:
1. Create a FooConfigUpdater service (e.g BlockConfigUpdater for block config entities)
This service is responsible for checking whether a config entity needs to be updated, doing the update, and throwing the deprecation error if the entity needed updating. This must be a service so the class property to flag that deprecations are enabled persists from the post_update hook into the pre_save hook.
The post_update hook then simply calls a needsFooBarUpdate
method on the FooConfigUpdater service and if that returns TRUE, the ConfigEntityUpdater class will save the config entity, which will then flow into the pre_save hook. The pre_save hook then does the actual config changes.
This pattern has worked quite well and is currently in use by a number of different core issues:
1. Deprecating block_content block settings https://git.drupalcode.org/project/drupal/-/merge_requests/6953/diffs
2. Updating EntityViewDisplay config https://git.drupalcode.org/project/drupal/-/merge_requests/11941/diffs
3. Updating image fields https://git.drupalcode.org/project/drupal/-/merge_requests/5544/diffs
And quite a few more.
We should standardise these classes with an interface + base class to make them easier to implement and reduce boilerplate.
Proposed resolution
Add an ConfigUpdaterInterface
with the following methods:
public function setDeprecationsEnabled(bool $enabled): void
public function updateConfigEntity(ConfigEntityInterface $entity): bool
Add a ConfigUpdaterBase
abstract class with the following code:
/**
* Flag determining whether deprecations should be triggered.
*/
protected bool $deprecationsEnabled = TRUE;
/**
* Stores which deprecations were triggered.
*/
protected array $triggeredDeprecations = [];
/**
* Sets the deprecations enabling status.
*
* @param bool $enabled
* Whether deprecations should be enabled.
*/
public function setDeprecationsEnabled(bool $enabled): void {
$this->deprecationsEnabled = $enabled;
}
Remaining tasks
Agree on implementation
Decide where these should live
Decide how much test coverage (if any) we need
API changes
New ConfigUpdater APIs