Config Storage Transform Event
A new Drupal\Core\Config\StorageTransformEvent with the name config.transform.export is dispatched when the export config storage is used. (See related change notice)
Symmetrically a new Drupal\Core\Config\StorageTransformEvent with the name config.transform.import is dispatched before the \Drupal\Core\Config\ConfigImporter imports the configuration.
The events are dispatched before the import or export take place without a guarantee that they do so in the end. In particular the import transformation event is dispatched before the interface shows the difference of configuration to import.
The transformed storage may be cached and the event may not be fired again for example if the active configuration has not changed.
Note: The dispatching of the event should not have any side effects. Event subscribers should only alter the configuration storage of the event.
These events allow modules to interact with the configuration deployment workflow. This was previously only possible with the contrib Config Filter module.
Example Usage
use Drupal\Core\Config\ConfigEvents;
use Drupal\Core\Config\StorageTransformEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class EventSubscriber implements EventSubscriberInterface {
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[ConfigEvents::STORAGE_TRANSFORM_IMPORT][] = ['onImportTransform'];
$events[ConfigEvents::STORAGE_TRANSFORM_EXPORT][] = ['onExportTransform'];
return $events;
}
/**
* The storage is transformed for importing.
*
* @param \Drupal\Core\Config\StorageTransformEvent $event
* The config storage transform event.
*/
public function onImportTransform(StorageTransformEvent $event) {
/** @var \Drupal\Core\Config\StorageInterface $storage */
$storage = $event->getStorage();
$site = $storage->read('system.site');
// Only change something if the sync storage has data.
if (!empty($site)) {
$site['name'] = 'Enforced site name';
// Write to the storage from the event to alter it.
$storage->write('system.site', $site);
}
}
/**
* The storage is transformed for exporting.
*
* @param \Drupal\Core\Config\StorageTransformEvent $event
* The config storage transform event.
*/
public function onExportTransform(StorageTransformEvent $event) {
/** @var \Drupal\Core\Config\StorageInterface $storage */
$storage = $event->getStorage();
$site = $storage->read('system.site');
// Prevent the slogan from being exported.
$site['slogan'] = '';
// Write to the storage from the event to alter it.
$storage->write('system.site', $site);
}
}
Systems invoking the \Drupal\Core\Config\ConfigImporter directly
A new config.import_transformer service (\Drupal\Core\Config\ImportStorageTransformer) facilitates dispatching the aforementioned import event.
The storage from which the configuration is about to be imported needs to be transformed before passing it to the StorageComparer. The transformation needs to happen regardless of whether the import takes place or the storage is only used to show a diff of what is about to be imported.
Before:
$storage = \Drupal::service('config.storage.sync');
$comparer = new StorageComparer($storage, $this->activeStorage, $this->configManager);
$importer = new ConfigImporter(
$comparer,
$this->eventDispatcher,
$this->configManager,
$this->lock,
$this->configTyped,
$this->moduleHandler,
$this->moduleInstaller,
$this->themeHandler,
$this->stringTranslation
);
After:
$storage = \Drupal::service('config.storage.sync');
// Do not use the service if it doesn't exist. This makes it backwards compatible.
if (\Drupal::getContainer()->has('config.import_transformer')) {
$storage = \Drupal::service('config.import_transformer')->transform($storage);
}
$comparer = new StorageComparer($storage, $this->activeStorage, $this->configManager);
$importer = new ConfigImporter(
$comparer,
$this->eventDispatcher,
$this->configManager,
$this->lock,
$this->configTyped,
$this->moduleHandler,
$this->moduleInstaller,
$this->themeHandler,
$this->stringTranslation
);
Comments
Excluding a single item?
How would you use this API to exclude a single config item so that its contents are neither exported to a file nor deleted during import if the file doesn't exist?
--
Damien McKenna
I wrote an example module
I wrote an example module when trying to do that. The readme goes into detail, because you do have to be careful what you are doing in each direction: https://git.drupalcode.org/sandbox/ekes-3187856/-/blob/1.0.x/README.md