In Drupal 7, one was able to retrieve the physical names of the database tables using some code like the following, it was pretty simple.
$field_definitions = field_info_fields();
foreach ($field_definitions as $field => $definition) {
$current_storage = $definition['storage']['details']['sql'][FIELD_LOAD_CURRENT];
$current_table = key($current_storage);
$revision_storage = $definition['storage']['details']['sql'][FIELD_LOAD_REVISION];
$revision_table = key($revision_storage);
}
In Drupal 9, the entity API changed for the better and now there are classes and services to pull this type of information. That's all well and good, I understand most of the concepts around this, but I cannot for the life of me seem to extrapolate how to get this same data.
My goal is to loop over all my entity types that implement ContentEntityTypeInterface, get their fields, then build an array looking something like so, I have a very specialized Drush script I'm trying to port over from Drupal 7.
$example = [
'node' => [
'field_something' => [
'current' => 'some_table_name'
'revision' => 'some_table_name'
]
],
'block' => [
'field_something' => [
'current' => 'some_table_name'
'revision' => 'some_table_name'
]
]
];
*Taking into account whether a field is actually revisionable in the first place, of course.
On my own, I determined for the most part that table names end up being like like $entityType . '__' . $field['name'] and $entityType . '_revision__' . $field['name'] but hardcoding my script breaks down when unique IDs are used. For example, custom blocks have table names like block_content_r__7fe666c7a4. I need to be able to pull that data out of the "field storage definition" of sorts.
Solution:
Per @Clive the solution was to get the storage class for each entity type, and then use it to retrieve the table mappings. This works great for non-base fields, but if you wanted a base field the solution would be different. Here is what I ended up with:
$fields = [];
foreach ($this->getContentEntityTypes() as $contentEntityType) {
$tableMapping = $this->entityTypeManager->getStorage($contentEntityType->id())->getTableMapping();
foreach ($this->entityFieldManager->getFieldStorageDefinitions($contentEntityType->id()) as $field) {
// We use requiresDedicatedTableStorage() to filter out base fields
if ($tableMapping->requiresDedicatedTableStorage($field)) {
$fieldInfo = [
'name' => $field->getName(),
'type' => $field->getType(),
'table' => $tableMapping->getDedicatedDataTableName($field)
];
if ($field->isRevisionable()) {
$fieldInfo['table_revision'] = $tableMapping->getDedicatedRevisionTableName($field);
}
$fields[$contentEntityType->id()][] = $fieldInfo;
}
}
}
return $fields;
I wrote a separate method to get my content entities, which the above code used.
function getContentEntityTypes() {
$contentEntityTypes = [];
$entity_type_definitions = $this->entityTypeManager->getDefinitions();
/* @var $definition EntityTypeInterface */
foreach ($entity_type_definitions as $entityType) {
if ($entityType instanceof ContentEntityTypeInterface && in_array(SqlEntityStorageInterface::class, class_implements($entityType->getStorageClass()))) {
$contentEntityTypes[] = $entityType;
}
}
return $contentEntityTypes;
}