Problem/Motivation
Right now Drupal core has logic to decide if base field data should be stored in the shared entity field data table (eg: node_field_data
), or in a dedicated table (eg: node__myfield
). This logic is contained in the DefaultTableMapping::allowsSharedTableStorage()
method:
/**
* Checks whether the given field can be stored in a shared table.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The field storage definition.
*
* @return bool
* TRUE if the field can be stored in a shared table, FALSE otherwise.
*/
public function allowsSharedTableStorage(FieldStorageDefinitionInterface $storage_definition) {
return !$storage_definition->hasCustomStorage() && $storage_definition->isBaseField() && !$storage_definition->isMultiple() && !$storage_definition->isDeleted();
}
Thus, a field will be saved to the shared table storage if a) it does not have custom storage, AND b) it is a base field, AND c) it is not a multi-value field, AND d) it is not deleted.
This means that single-value base fields will ALWAYS be stored in the shared table. While this is beneficial to reducing the number of table JOIN
s required, it is not always desirable.
If a field is not required, it's possible to end up with a lot of empty cells / sparse data in the shared table, which could otherwise be avoided by a dedicated table. This is compounded by fields that add a lot of columns (like Geofields which add 9).
And more generally, it would be nice to provide the option to developers to explicitly declare that some fields should be stored in dedicated tables. Even though Drupal tries to abstract a lot of these low-level decisions, it is still useful to expose some of them to the developer so they can make the right choice for their particular application.
Proposed resolution
I propose we add two new methods to the BaseFieldDefinition
class: setDedicatedTable()
and hasDedicatedTable()
The latter can then be added as an additional condition in the allowsSharedTableStorage()
method logic (described above).
Thus, a developer defining a new base field could do something like this to specify that the field data should be saved in a dedicated table:
$fields['myfield'] = BaseFieldDefinition::create('string')
->setLabel(t('My field'))
->setDedicatedTable(TRUE);
The method names setDedicatedTable()
and hasDedicatedTable()
were chosen to match the existing pattern set by setCustomStorage()
and hasCustomStorage()
methods, but open to other ideas if you think those don't perfectly convey their purpose.
Remaining tasks
... (tbd)
User interface changes
None.
API changes
This would change the API surface of FieldStorageDefinitionInterface
to have an additional method: hasDedicatedTable()
(returns boolean true/false).
Data model changes
None.
Release notes snippet
... (tbd)