Skip to content

Added 'FieldClassifier' with nine F-row predicates and rewrote field-expansion pipeline.#359

Merged
AlexSkrypnyk merged 2 commits intomasterfrom
feature/field-classifier
Apr 28, 2026
Merged

Added 'FieldClassifier' with nine F-row predicates and rewrote field-expansion pipeline.#359
AlexSkrypnyk merged 2 commits intomasterfrom
feature/field-classifier

Conversation

@AlexSkrypnyk
Copy link
Copy Markdown
Collaborator

Summary

Introduces FieldClassifier and FieldClassifierInterface with nine F-row predicates (F1-F9) that classify every Drupal field by origin (base / configurable / bundle-storage-backed) and storage profile (standard / computed / custom). Core::expandEntityFields() is rewritten to route fields through the classifier — only F1 (base standard), F5 (configurable), and F9 (bundle-storage-backed) rows enter the handler pipeline, which eliminates the silent mis-classification of computed and non-writable base fields. DefaultHandler is tightened to throw a clear, actionable error for any field type whose schema is not single-column value, enforcing a loud-failure policy so broken handlers surface immediately. A full F-row truth table is documented in src/Drupal/Driver/Core/Field/README.md.

Stack

This PR is #2 of 4 in a stacked series:

Merge in order. This PR depends on #358.

Changes

Field classifier

  • Added FieldClassifierInterface with nine predicates: fieldIsBaseStandard, fieldIsBaseComputed, fieldIsBaseCustom, fieldIsConfigurableStandard, fieldIsConfigurableComputed, fieldIsConfigurableCustom, fieldIsBundleStorageBacked, fieldIsConfigurable, fieldIsBase.
  • Added FieldClassifier implementing the interface, backed by EntityFieldManagerInterface.
  • Core holds a lazily created FieldClassifierInterface instance exposed via classifier() on CoreInterface; subclasses override createFieldClassifier() to inject a version-specific implementation.

Pipeline rewrite

  • Core::expandEntityFields() no longer accepts $base_fields; bundle is resolved automatically via resolveBundleFromEntity() (bundle key → step_bundle → entity type id).
  • Core::getEntityFieldTypes() signature changed from array $base_fields = [] to ?string $bundle = NULL; the method now gates inclusion on classifier predicates (F1 OR F5 OR F9) rather than a hard-coded storage-config check.
  • Core::expandEntityBaseFields() removed (was a thin wrapper; callers use expandEntityFields() directly).
  • Core::detectBaseFieldsOnEntity() replaced by resolveBundleFromEntity().
  • Core::fieldExists() and Core::fieldIsBase() removed; use classifier() predicates instead.
  • Core::getFieldHandler() now passes the resolved bundle to getEntityFieldTypes().

DefaultHandler loud-failure policy

  • DefaultHandler::expand() now throws \RuntimeException for any field whose storage schema is not a single value column, surfacing handler gaps immediately rather than silently returning garbage.

EntityReferenceRevisionsHandler

  • Added handler for entity_reference_revisions fields (paragraphs, media, and other revision-tracked references); mirrors EntityReferenceHandler but targets target_revision_id alongside target_id.

Documentation

  • Added src/Drupal/Driver/Core/Field/README.md with the F-row truth table, column definitions, and guidance on which rows enter the pipeline.
  • UPGRADING.md updated with migration notes for removed predicates (fieldExists, fieldIsBase), the removed FieldCapabilityInterface, and the changed getEntityFieldTypes() signature.

Removed

  • src/Drupal/Driver/Capability/FieldCapabilityInterface.php — contract superseded by classifier predicates.
  • CoreInterface no longer extends FieldCapabilityInterface.
  • DrupalDriverInterface no longer re-exports fieldExists / fieldIsBase.

Tests

  • Added FieldClassifierTest (221 lines, unit, all nine predicates).
  • Added EntityReferenceRevisionsHandlerTest (163 lines, unit).
  • Expanded DefaultHandlerTest with loud-failure coverage.
  • Added CoreEntityCreateModerationStateKernelTest — round-trip kernel test for F3 (writable computed base field moderation_state).
  • Updated CoreFieldMethodsTest and CoreEntityMethodsKernelTest for the new signatures.

Before / After

BEFORE
------
expandEntityFields($type, $entity, $base_fields)
  getEntityFieldTypes($type, $base_fields)
    for each storage definition:
      if FieldStorageConfig  →  add (F5 only)
      if in $base_fields     →  add (any base field, no filter)
  for each field:
    handler->expand()        ← computed/non-writable fields slip through here

AFTER
-----
expandEntityFields($type, $entity)
  resolveBundleFromEntity()  →  bundle
  getEntityFieldTypes($type, bundle)
    for each definition (storage + base + bundle):
      classifier->fieldIsBaseStandard?      →  F1: add
      classifier->fieldIsConfigurable?      →  F5: add (scoped to bundle)
      classifier->fieldIsBundleStorageBacked? → F9: add
  for each field (id/bundle keys skipped):
    handler->expand()        ← only writable, handler-eligible fields reach here

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 273274ec-79c5-44fd-a011-378b1b26a95d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/field-classifier

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Base automatically changed from feature/driver-interface to master April 28, 2026 08:12
@AlexSkrypnyk AlexSkrypnyk merged commit ff6efb1 into master Apr 28, 2026
1 check passed
@AlexSkrypnyk AlexSkrypnyk deleted the feature/field-classifier branch April 28, 2026 08:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant