Not re-opening #1253194: fields are deleted when reverting exported bundle entities given its age, but I noticed something that went into Entity API in that patch.
- Suppose I have a feature "Feature X" with 2 exported bundle entities: "Entity A" and "Entity B"
- I override Entity A, while deleting Entity B from the Feature X
- Feature X now shows as overridden for Entity A and doesn't show entity B at all
- I choose to revert Feature X, which triggers a delete for Entity A
EntityAPIControllerExportable::delete()triggersEntityAPIController::delete()for Entity AEntityAPIController::delete()invokesEntityAPIControllerExportable::invoke()which correctly sets$is_reverttoTRUE, nothing happens to Entity A's fieldsEntityAPIControllerExportable::delete()runs further and notices Entity A hadENTITY_IN_CODEand triggersentity_defaults_rebuild()_entity_defaults_rebuild()figures Entity B used to live in code, but no longer does, so deletes it because it wasn't overriddenEntityAPIControllerExportable::delete()triggersEntityAPIController::delete()for Entity BEntityAPIController::delete()invokesEntityAPIControllerExportable::invoke()which incorrectly sets$is_reverttoTRUE, nothing happens to Entity B's fields
See below why this happens (snippet from EntityAPIControllerExportable::invoke()):
if ($hook == 'delete') {
// To ease figuring out whether this is a revert, make sure that the
// entity status is updated in case the providing module has been
// disabled.
// THE FEATURE STILL EXISTS, SO ITS BUNDLE ENTITIES ARE NOT
// BEING FLAGGED AS ENTITY_CUSTOM, CAUSING $is_revert TO BE SET TO TRUE.
if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE) && !module_exists($entity->{$this->moduleKey})) {
$entity->{$this->statusKey} = ENTITY_CUSTOM;
}
// THIS LEADS ENTITY API TO THINK THEY ARE ALL BEING REVERTED.
$is_revert = entity_has_status($this->entityType, $entity, ENTITY_IN_CODE);
}
This is something I ran into after a long, hard review of Entity API's revert handling (as I needed to know the ins and outs for the Group module). I chose not to write a patch yet for the following reasons:
- We could fix this in
EntityAPIControllerExportable::invoke()and potentially keep other places where we need an $is_revert flag in the dark - Or we could adapt
EntityDefaultUIController::applyOperation()andEntityDefaultFeaturesController::revert()to set an$is_revertflag on the entity before deleting it and check for that flag from now on.
Perhaps I'm stating the obvious, but setting an $is_revert flag would persist through all delete hooks until EntityAPIController::load() is called after EntityAPIController::delete() has run. This should be fine, really, and it wouldn't break backwards compatibility.
I'd love to hear your thoughts on this, Wolfgang.
Comments
Comment #1
kenorb commentedSame issue I guess: #2698553: entity_defaults_rebuild triggers another entity_defaults_rebuild causing an infinite loop
Comment #2
kristiaanvandeneyndeThis doesn't seem related at first glance. If anything, this issue and the duplicate I somehow created at #2309777: Potential data corruption in EntityAPIControllerExportable are about how Entity API incorrectly sets $is_revert, leading to orphaned field tables.
How this would trigger another entity_delete() is unclear to me. Have you checked your hook_entity_delete() and hook_ENTITY_delete() implementations?
Comment #3
kristiaanvandeneyndeAlso...