Though it’s ideal to centralize entity and schema management together within Drupal, there are possible use cases where the two must be managed independently:
- Drupal entities that are based on tables in an external DB
- Manual schema updates for tables with exiting data that are considered unsafe from a cross-DB support perspective, but may otherwise be safe in controlled situations (e.g. increase varchar length on mySQL).
Our case is specific to #1. We have Drupal entities based off tables in an external DB (using
base_table = "dbname.tablename" convention), and the related schema is managed exclusively by another platform. This means that when schema changes are deployed externally we need to update the relevant entity definitions and installed schema definitions in Drupal without triggering the actual schema updates themselves (e.g. no
CREATE/DROP/ALTER TABLE... calls). The best way to tackle this problem has always been a bit unclear, and some of the new constraints introduced in 8.7.x seem to cloud the matter even further.
It seems that there are several Drupal-specific layers that need to be navigated here, including the entity definition, the entity storage definition, the last installed schema definition, the actual schema management API and various caches. The interplay between these layers had been difficult to pin down.
Some solutions proposed in forums involve manual manipulation of each API layer and often ad-hoc workarounds (direct updates to key_value DB records) that seem quite questionable. Examples are here, here and the “Updating an existing entity type” notes here. There also appears to be some discussion around overall limitations in field-specific schema updates here.
Some relief may come in the form of the
EntityDefinitionUpdateManagerInterface which seems to serve as a central place to abstract these various layers away, but it’s not clear which methods operate purely on storage/schema definitions and not the actual DB schema itself. For example, I have had some success (re)using the
::installEntityType() method to deploy changes after externally updating the DB schema, updating the related Drupal entity definition and then running:
$ entity_type = \Drupal::entityTypeManager()->getDefinition('my_custom_entity_type'); $ entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $ entity_definition_update_manager->installEntityType($ entity_type);
This seems to update the related entity/field storage definitions and the schema definitions and does not seem to alter the DB schema (I guess because the related table is detected as already existing). But given that this method is documented for once-off use (not ongoing re-install use) this feels like “off-label” use with unpredictable side-effects.
I also suppose that a custom entity storage definition could be justified to deal with all this, but I assume that would require re-defining or re-wiring quite a few dependencies (notably the low-level SQL management) that otherwise work well with the native entity storage.
So what is the best practice way to make Drupal aware of externally managed schema updates that impact Drupal entities?
I have a feeling that fully understanding this also requires a good explanation of how APIs used to manage Entity/Field definitions/storage are independent (or not) from core schema management tools like the Schema API and