Problem/Motivation
The field exporter and importer only handle two kinds of field definitions:
FieldConfig— custom fields attached to a bundleBaseFieldOverride— a config entity created when a base field label has already been overridden per bundle
Plain base fields — base fields such as node.title for which no BaseFieldOverride config entity yet
exists — are silently skipped in all three processing loops inside EntityLabelsFieldExporter::getEntityBundleData()
because each loop guards on instanceof FieldConfigInterface. FieldDefinitionInterface, the correct shared
interface, is never checked.
The importer has the same gap: when neither FieldConfig::load() nor BaseFieldOverride::load() returns a
result, the row is skipped and recorded in null_fields, even though the field exists as a plain base field and a
BaseFieldOverride could be created on first import.
Steps to reproduce
- Install the module on a standard Drupal site with a
nodecontent type. - Do not create a
BaseFieldOverridefornode.titleon any bundle (the default
state). - Export fields via the UI or Drush —
titleis absent from the CSV. - Try importing a row with
field_name = title— it is skipped and added tonull_fields.
Proposed resolution
Exporter (EntityLabelsFieldExporter)
Remove the instanceof FieldConfigInterface guards in the three loops inside getEntityBundleData(),
replacing them with instanceof FieldDefinitionInterface (which all entries in $field_definitions already
satisfy).
Widen the getFieldRows() and getFieldDefinitionAllowedValues() parameter types from
FieldConfigInterface to FieldDefinitionInterface. Split the label/description resolution path:
- For
FieldConfigInterfaceinstances (includingBaseFieldOverride), continue reading from the translated
config viagetConfigDependencyName()as before. - For plain base fields (not
FieldConfigInterface), read label and description directly from the definition and
append"Base field"to thenotescolumn.
BaseFieldOverride already implements FieldConfigInterface, so the existing
"Base field
override"note path is unchanged.
Importer (EntityLabelsFieldImporter)
After the existing FieldConfig::load() ?? BaseFieldOverride::load() lookup returns null, add a fallback:
check EntityFieldManagerInterface::getBaseFieldDefinitions() for the field name and, if found, call
BaseFieldOverride::createFromBaseFieldDefinition(). The new override is then labelled, described, and saved through the
same existing path that already handles persisted overrides.
EntityFieldManagerInterface is added as a constructor parameter (autowired — no service YAML change needed).
Remaining tasks
- Review patch
- Confirm behaviour for multilingual sites (plain base field rows in non-default languages)
User interface changes
None. Plain base fields now appear in the field report and CSV export. No UI elements are added or changed.
API changes
EntityLabelsFieldExporter::getFieldRows() and getFieldDefinitionAllowedValues() now accept
FieldDefinitionInterface instead of FieldConfigInterface. Both are private methods, so there is
no public API change.
EntityLabelsFieldImporter gains an EntityFieldManagerInterface constructor parameter. The service is
autowired, so no service definition update is required for standard sites. Custom instantiation outside the container will need to
pass the additional argument.
Data model changes
None at rest. On first import of a plain base field, a new BaseFieldOverride config entity is created — the same
entity type the importer already creates and saves in the normal override path.
Issue fork entity_labels-3581426
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
jrockowitz commentedComment #4
jrockowitz commentedComment #6
jrockowitz commented