When a configuration entity that acts as a bundle for another entity is first saved, it does not have an "original ID" yet. If that configuration entity is then re-saved during Entity::postSave() or hook_entity_insert(), the site shows a blank screen (WSOD).
This is because ConfigEntityBundleBase::preSave() throws an exception if the entity ID differs from the original ID. Of course this is always the case for new bundle entities, as they have NULL for their original ID. See below for the relevant code:
public function preSave(EntityStorageInterface $storage) {
parent::preSave($storage);
// Only handle renames, not creations.
if (!$this->isNew() && $this->getOriginalId() !== $this->id()) {
$bundle_type = $this->getEntityType();
$bundle_of = $bundle_type->getBundleOf();
if (!empty($bundle_of)) {
throw new ConfigNameException("The machine name of the '{$bundle_type->getLabel()}' bundle cannot be changed.");
}
}
}
However, EntityStorageBase::doPostSave has a fix for this, but it's being called too late:
protected function doPostSave(EntityInterface $entity, $update) {
$this->resetCache(array($entity->id()));
// The entity is no longer new.
$entity->enforceIsNew(FALSE);
// Allow code to run after saving.
$entity->postSave($this, $update);
$this->invokeHook($update ? 'update' : 'insert', $entity);
// After saving, this is now the "original entity", and subsequent saves
// will be updates instead of inserts, and updates must always be able to
// correctly identify the original entity.
$entity->setOriginalId($entity->id());
unset($entity->original);
}
Proposed resolution:
- Move the relevant piece of code above the postSave and invokeHook for new entities and leave it below the hooks for updated entities.
- Alternatively, do the above in a brand new ConfigEntityStorageBase class override of ::postSave().
Example use case:
Config entities can have plugin collections by implementing EntityWithPluginCollectionInterface. After saving, one could let other modules try to install "default" plugins on the config entity. Doing so would require a re-save of the config entity, leading to the exception thrown.