Skip to content

Added a dedicated field value-shape classifier gating the default handler, and deprecated pass-through handlers.#386

Merged
AlexSkrypnyk merged 6 commits into
masterfrom
feature/default-field-detect
Jul 7, 2026
Merged

Added a dedicated field value-shape classifier gating the default handler, and deprecated pass-through handlers.#386
AlexSkrypnyk merged 6 commits into
masterfrom
feature/default-field-detect

Conversation

@AlexSkrypnyk

@AlexSkrypnyk AlexSkrypnyk commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

When a field type has no dedicated handler, Core routes it through a value-shape classifier before falling back to DefaultHandler. Because a field's value shape (scalar vs entity-reference vs complex) is orthogonal to the origin/storage F-row axis that FieldClassifier owns, this is a separate, focused abstraction - FieldShapeClassifierInterface / FieldShapeClassifier - built with the same factory and version-override discipline as FieldClassifier (Core::createFieldShapeClassifier(), overridable by a Core{N}\Field\FieldShapeClassifier).

Core::getFieldHandler() asks the shape classifier two predicates - fieldIsEntityReference() and fieldIsComplexValue() - and throws an actionable exception when either is true, because those shapes cannot be authored as a plain scalar (an entity-reference id the author cannot know; a complex/nested value with no scalar form). The classifier reads only the stored (non-computed) property definitions and enumerates no field-type or data-type strings, so datetime strings, booleans, and list keys are plain scalars the default relays verbatim - their translation stays in dedicated handlers.

Detection is proactive rather than try/catch, because both shapes fail silently (a label persisted as a bogus id, a nested value flattened), so the field is refused at handler resolution rather than after a corrupt save. FieldClassifier is unchanged - it remains exactly the nine F-row predicates.

Deprecations

TextHandler, TextLongHandler, TextWithSummaryHandler, and ColorFieldTypeHandler handle field types whose columns are plain scalars the generic default now relays, so they are redundant. They remain registered and functional but are @deprecated for removal in drupal-driver:4.0.0, kept for consumers that extend or reference them. On removal, their field types fall through to DefaultHandler with no behavioural change.

Changes

  • Added FieldShapeClassifierInterface / FieldShapeClassifier - a dedicated value-shape classifier with fieldIsEntityReference() and fieldIsComplexValue() predicates over a field's stored (non-computed) property definitions.
  • Added Core::createFieldShapeClassifier() / getFieldShapeClassifier() (declared on CoreInterface), mirroring the F-row classifier's factory + lazy-getter + version-override pattern.
  • Core::getFieldHandler() consults the shape classifier when it would fall back to DefaultHandler and throws an exception naming the field, type, entity type, bundle, and why the default cannot relay it.
  • Reduced DefaultHandler to a pure pass-through; the old single-column getColumns() guard is gone.
  • Marked TextHandler, TextLongHandler, TextWithSummaryHandler, and ColorFieldTypeHandler @deprecated for 4.0.0.
  • Added FieldShapeClassifierTest and DefaultHandlerEnforcementKernelTest; pointed FieldTypeCoverageKernelTest at the shape classifier. FieldClassifier and its test are untouched.

Before / After

BEFORE
──────
getFieldHandler(field)
   ├ registered handler? ─ yes ─► that handler
   └ no ─► DefaultHandler::doExpand()
             guard: count(columns) == 1 && key == "value"
                satisfied ─► relay records
                else ──────► throw "N column(s) ... single-column only"

  text, text_long, text_with_summary, color_field_type tripped the guard,
  so each shipped a pass-through handler class solely to satisfy it.


AFTER
─────
  FieldClassifier (F-rows)            FieldShapeClassifier (value shape)
  origin / storage profile            stored (non-computed) properties
        │                                       │
        │  getEntityFieldTypes()                │  getFieldHandler() fallback
        ▼                                       ▼
  "does it enter the pipeline?"         "can the default relay it?"

getFieldHandler(field)
   ├ registered handler? ─ yes ─► that handler
   └ no ─► Core asks FieldShapeClassifier
              ├ fieldIsEntityReference() ─► Core throws (needs a handler)
              ├ fieldIsComplexValue()    ─► Core throws (needs a handler)
              └ neither (plain scalar)   ─► DefaultHandler relays verbatim
                     string, integer, datetime strings, booleans, list keys,
                     and any future contrib scalar field

  Two orthogonal, equally-disciplined classifiers instead of one class doing
  both jobs - or classification logic buried inside the default handler.

Summary by CodeRabbit

  • New Features

    • Added smarter field handling so plain scalar fields can pass through automatically, while unsupported complex or reference fields are now rejected with clearer errors.
    • Added support for classifying field shapes to improve handler selection.
    • Added test fixture field types for scalar and reference-style fields.
  • Bug Fixes

    • Removed stricter fallback checks that blocked valid multi-column scalar fields.
    • Improved handling for color, text, and summary-related fields by routing them through the generic path where appropriate.
  • Chores

    • Updated documentation and test coverage to match the new field-handling behavior.
    • Marked several redundant handlers as deprecated ahead of a future removal.

…ions.

'DefaultHandler' now inspects a field's stored (non-computed) property definitions and relays the normalised records verbatim only when every stored property is a plain scalar the caller authors as-is. A property that needs a translation the default cannot perform - an entity-reference target, a 'datetime_iso8601'/'duration_iso8601' string, or a complex/nested value - makes the field ineligible, and expand() throws a message naming the field and the offending property. Detection is proactive rather than try/catch because those translations fail silently (a label persisted as a bogus id, a timezone-shifted date).

Removed the pure pass-through handlers 'TextHandler', 'TextLongHandler', 'TextWithSummaryHandler', and 'ColorFieldTypeHandler': their field types are plain scalars the default now absorbs, as is any future contrib field of the same shape.

'date_recur' keeps its handler because its 'value'/'end_value' columns are 'datetime_iso8601' (inherited from 'daterange'), structurally identical to fields that need timezone conversion, so the default rejects it and the verbatim pass-through must be declared by a handler.

'FieldTypeCoverageKernelTest' classifies via the shared 'DefaultHandler::unsupportedPropertyReason()', and the text/color kernel round-trips are consolidated into 'DefaultHandlerKernelTest'.
'expectExceptionMessage()' keeps only its last call, so the earlier wrapper-text assertion was silently dropped. Combining both fragments into a single 'expectExceptionMessageMatches()' verifies the message as a whole.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces FieldShapeClassifier/FieldShapeClassifierInterface to classify a field's stored value shape (entity-reference vs. complex vs. plain scalar), integrates the classifier into Core::getFieldHandler() to guard DefaultHandler usage, simplifies DefaultHandler::doExpand() into a pure pass-through, deprecates ColorFieldTypeHandler, TextHandler, TextLongHandler, and TextWithSummaryHandler, updates related tests/README, and adds a driver_field_test fixture module with a kernel test.

Changes

DefaultHandler classification and enforcement

Layer / File(s) Summary
FieldShapeClassifier contract and implementation
src/Drupal/Driver/Core/Field/FieldShapeClassifierInterface.php, src/Drupal/Driver/Core/Field/FieldShapeClassifier.php, tests/Drupal/Tests/Driver/Unit/Core/Field/FieldShapeClassifierTest.php
New interface and class classify stored field properties as entity-reference or complex/nested values, with unit tests covering scalar, datetime, computed, reference, and complex cases.
Core enforcement of DefaultHandler eligibility
src/Drupal/Driver/Core/Core.php, src/Drupal/Driver/Core/CoreInterface.php, tests/Drupal/Tests/Driver/Unit/Core/CoreFieldHandlerLookupTest.php
Core gains getFieldShapeClassifier()/createFieldShapeClassifier() and a new assertDefaultHandlerCanMarshal() guard invoked from getFieldHandler() that throws RuntimeException for unsafe field shapes.
DefaultHandler pass-through simplification
src/Drupal/Driver/Core/Field/DefaultHandler.php, tests/Drupal/Tests/Driver/Unit/Core/Field/DefaultHandlerTest.php
doExpand() no longer validates column shape and returns records unchanged; tests updated to use a reflection-based helper and drop old exception cases.
Deprecation of redundant scalar handlers
src/Drupal/Driver/Core/Field/ColorFieldTypeHandler.php, TextHandler.php, TextLongHandler.php, TextWithSummaryHandler.php
Handlers marked deprecated for removal in drupal-driver 4.0.0; corresponding unit tests removed.
FieldTypeCoverageKernelTest safety check update
tests/Drupal/Tests/Driver/Kernel/Core/Field/FieldTypeCoverageKernelTest.php
isDefaultHandlerSafe() now uses the field shape classifier instead of inspecting storage schema columns.
driver_field_test fixture module and kernel test
composer.json, tests/fixtures/modules/driver_field_test/*, tests/Drupal/Tests/Driver/Kernel/Core/Field/CustomModuleFieldKernelTest.php
New fixture module with scalar and reference field type plugins registered via composer path repository; kernel test verifies scalar fields round-trip and reference fields without a dedicated handler are rejected.
README documentation updates
src/Drupal/Driver/Core/Field/README.md
Truth table and policy documentation updated to describe classifier-driven DefaultHandler eligibility and handler deprecations.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • jhedstrom/DrupalDriver#353: Both PRs modify Core::getFieldHandler() resolution logic, one adding registry/fallback and this one adding classifier-based guarding.
  • jhedstrom/DrupalDriver#372: Both PRs modify DefaultHandler.php's expand contract and its runtime validation/loud-failure behavior.
  • jhedstrom/DrupalDriver#375: This PR deprecates ColorFieldTypeHandler and removes its unit test, directly building on that PR's introduction of the handler.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: new value-shape classification for default-handler gating plus deprecation of pass-through handlers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/default-field-detect

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.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Code coverage (threshold: 95%)



Code Coverage Report Summary:
  Classes: 58.82% (20/34)
  Methods: 89.52% (222/248)
  Lines:   96.28% (1241/1289)

Per-class coverage
Drupal\Driver\Alias\CreationAliasRegistryTrait               100.00%
Drupal\Driver\Alias\RolesAlias                                87.50%
Drupal\Driver\BlackboxDriver                                 100.00%
Drupal\Driver\Core\Alias\AuthorAlias                          90.48%
Drupal\Driver\Core\Alias\ParentTermAlias                      88.24%
Drupal\Driver\Core\Alias\VocabularyMachineNameAlias           88.89%
Drupal\Driver\Core\Core                                       95.81%
Drupal\Driver\Core\Field\AbstractHandler                      95.74%
Drupal\Driver\Core\Field\AddressHandler                       94.83%
Drupal\Driver\Core\Field\BooleanHandler                      100.00%
Drupal\Driver\Core\Field\ColorFieldTypeHandler                 0.00%
Drupal\Driver\Core\Field\DateRecurHandler                    100.00%
Drupal\Driver\Core\Field\DaterangeHandler                    100.00%
Drupal\Driver\Core\Field\DatetimeHandler                     100.00%
Drupal\Driver\Core\Field\DefaultHandler                      100.00%
Drupal\Driver\Core\Field\EmbridgeAssetItemHandler              0.00%
Drupal\Driver\Core\Field\EntityReferenceHandler               94.44%
Drupal\Driver\Core\Field\EntityReferenceRevisionsHandler      86.05%
Drupal\Driver\Core\Field\FieldClassifier                      94.44%
Drupal\Driver\Core\Field\FieldShapeClassifier                100.00%
Drupal\Driver\Core\Field\FileHandler                         100.00%
Drupal\Driver\Core\Field\ImageHandler                        100.00%
Drupal\Driver\Core\Field\LinkHandler                          94.00%
Drupal\Driver\Core\Field\ListFloatHandler                    100.00%
Drupal\Driver\Core\Field\ListHandlerBase                     100.00%
Drupal\Driver\Core\Field\ListIntegerHandler                    0.00%
Drupal\Driver\Core\Field\ListStringHandler                     0.00%
Drupal\Driver\Core\Field\NameHandler                          96.36%
Drupal\Driver\Core\Field\OgStandardReferenceHandler            0.00%
Drupal\Driver\Core\Field\SmartdateHandler                    100.00%
Drupal\Driver\Core\Field\SupportedImageHandler               100.00%
Drupal\Driver\Core\Field\TextHandler                           0.00%
Drupal\Driver\Core\Field\TextLongHandler                       0.00%
Drupal\Driver\Core\Field\TextWithSummaryHandler                0.00%
Drupal\Driver\Core\Field\TimeHandler                          91.67%
Drupal\Driver\DrupalDriver                                    98.86%
Drupal\Driver\Drush\DrushResult                              100.00%
Drupal\Driver\DrushDriver                                    100.00%
Drupal\Driver\Entity\EntityStub                              100.00%
Drupal\Driver\Exception\BootstrapException                   100.00%
Drupal\Driver\Exception\CreationAliasResolutionException       0.00%
Drupal\Driver\Exception\Exception                            100.00%
Drupal\Driver\Exception\UnsupportedDriverActionException     100.00%

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/fixtures/ConsumerProject/Driver/Field/DatetimeHandler.php (1)

20-29: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a less loaded timestamp for the marker constant.

The MARKER value 2001-09-11T08:46:00 matches the well-known time of the September 11 attacks. Functionally it works fine as a distinct sentinel, but picking an arbitrary/less symbolically-charged timestamp (e.g. 1999-12-31T23:59:59) avoids any unintended association in test fixture data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/fixtures/ConsumerProject/Driver/Field/DatetimeHandler.php` around lines
20 - 29, The DatetimeHandler MARKER constant uses a timestamp with an unintended
real-world association; replace the current sentinel in DatetimeHandler::MARKER
with a neutral ISO 8601 value that is still clearly distinct from the input
date, and keep the rest of the handler behavior unchanged so the fixture
continues proving the custom handler ran.
src/Drupal/Driver/Core/Field/README.md (1)

53-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Spelling variant inconsistency: "normalize" vs "normalise".

Line 40 in this same doc uses "normalised"; line 56 switches to "normalize".

✏️ Proposed fix
-Internally, they normalize a scalar to `[$scalar]` before returning the storage
+Internally, they normalise a scalar to `[$scalar]` before returning the storage
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Drupal/Driver/Core/Field/README.md` around lines 53 - 58, The README has
a spelling-variant inconsistency in the cardinality section: the term used in
this passage should match the earlier “normalised” wording already used in the
same document. Update the wording in the Cardinality description to use the same
British spelling throughout, and keep the reference consistent with the
surrounding Field README text.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/Drupal/Driver/Core/Field/README.md`:
- Around line 53-58: The README has a spelling-variant inconsistency in the
cardinality section: the term used in this passage should match the earlier
“normalised” wording already used in the same document. Update the wording in
the Cardinality description to use the same British spelling throughout, and
keep the reference consistent with the surrounding Field README text.

In `@tests/fixtures/ConsumerProject/Driver/Field/DatetimeHandler.php`:
- Around line 20-29: The DatetimeHandler MARKER constant uses a timestamp with
an unintended real-world association; replace the current sentinel in
DatetimeHandler::MARKER with a neutral ISO 8601 value that is still clearly
distinct from the input date, and keep the rest of the handler behavior
unchanged so the fixture continues proving the custom handler ran.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 089f5b6f-de09-4a15-987f-d36efed9593d

📥 Commits

Reviewing files that changed from the base of the PR and between c669584 and 7a9226b.

📒 Files selected for processing (20)
  • src/Drupal/Driver/Core/Field/ColorFieldTypeHandler.php
  • src/Drupal/Driver/Core/Field/DefaultHandler.php
  • src/Drupal/Driver/Core/Field/README.md
  • src/Drupal/Driver/Core/Field/TextHandler.php
  • src/Drupal/Driver/Core/Field/TextLongHandler.php
  • src/Drupal/Driver/Core/Field/TextWithSummaryHandler.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/ColorFieldTypeHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/CustomCoreKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/DefaultHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/FieldHandlerRegistryKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/FieldTypeCoverageKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/TextHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/TextLongHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/TextWithSummaryHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/ColorFieldTypeHandlerTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/DefaultHandlerTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/TextHandlerTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/TextLongHandlerTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/TextWithSummaryHandlerTest.php
  • tests/fixtures/ConsumerProject/Driver/Field/DatetimeHandler.php
💤 Files with no reviewable changes (12)
  • tests/Drupal/Tests/Driver/Unit/Core/Field/TextWithSummaryHandlerTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/TextLongHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/TextHandlerTest.php
  • src/Drupal/Driver/Core/Field/TextHandler.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/ColorFieldTypeHandlerKernelTest.php
  • src/Drupal/Driver/Core/Field/TextWithSummaryHandler.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/TextWithSummaryHandlerKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/TextHandlerKernelTest.php
  • src/Drupal/Driver/Core/Field/TextLongHandler.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/TextLongHandlerTest.php
  • src/Drupal/Driver/Core/Field/ColorFieldTypeHandler.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/ColorFieldTypeHandlerTest.php

'DefaultHandler::unsupportedPropertyReason()' now rejects only the two shapes the generic type system exposes - an entity-reference target ('DataReferenceTargetDefinition') and a complex or nested value ('ComplexDataDefinitionInterface'/'ListDataDefinitionInterface'). It enumerates no field-type or data-type strings, so it never rejects a field for being a datetime, boolean, or list; those are scalars it relays as-is.

Timezone-aware conversion stays in the dedicated 'DatetimeHandler', 'DaterangeHandler', and 'DateRecurHandler' where it belongs, rather than being detected by the default. Updated the unit test and the README classification policy to match.
…ated pass-through handlers.

The property-shape classification - rejecting an entity-reference target or a complex/nested value - now lives in 'FieldClassifier::fieldDefaultExpandReason()' rather than inside the default handler. 'Core::getFieldHandler()' consults it before falling back to 'DefaultHandler' and throws the actionable message, so 'DefaultHandler' is a pure pass-through again. The classifier enumerates no field-type or data-type strings; value translation stays in the dedicated handlers.

Restored 'TextHandler', 'TextLongHandler', 'TextWithSummaryHandler', and 'ColorFieldTypeHandler' as '@deprecated' for removal in 4.0.0. Their columns are plain scalars the generic default now relays, but they stay registered and functional for consumers that extend or reference them; on removal their types fall through to 'DefaultHandler' unchanged.

Added a kernel test proving Core rejects an unhandled entity-reference field at resolution, and pointed the coverage test and unit tests at the shared classifier method.
@AlexSkrypnyk AlexSkrypnyk changed the title Made 'DefaultHandler' self-classify field types by their stored property definitions. Added a generic classifier gate for the default field handler and deprecated pass-through handlers. Jul 7, 2026
…ction.

The 'can the default relay this field' decision is a value-shape question - scalar vs entity-reference vs complex - which the README calls orthogonal to the F-row (origin/storage) axis 'FieldClassifier' owns. It now lives in its own 'FieldShapeClassifier'/'FieldShapeClassifierInterface' with two predicates, 'fieldIsEntityReference()' and 'fieldIsComplexValue()', mirroring 'FieldClassifier''s factory and version-override discipline via 'Core::createFieldShapeClassifier()'.

'Core::getFieldHandler()' consults the shape classifier before falling back to 'DefaultHandler' and throws when the field is an entity reference or a complex/nested value. 'FieldClassifier' is reverted to the nine F-row predicates only - the misplaced classification method is gone from it.

Added 'FieldShapeClassifierTest'; 'FieldTypeCoverageKernelTest' and the Core enforcement (proved by 'DefaultHandlerEnforcementKernelTest') consult the new classifier.
@AlexSkrypnyk AlexSkrypnyk changed the title Added a generic classifier gate for the default field handler and deprecated pass-through handlers. Added a dedicated field value-shape classifier gating the default handler, and deprecated pass-through handlers. Jul 7, 2026
The 'driver_field_test' fixture module - wired in through a composer path repository, the same mechanism as the DrupalExtension-smoke leg - ships two custom field types the driver has no handler for: 'driver_test_scalar' (plain-scalar columns) and 'driver_test_reference' (an entity-reference target column). It stands in for any contrib module that introduces its own field type.

'CustomModuleFieldKernelTest' drives both through the real 'Core' with every built-in handler registered: the scalar type rides 'DefaultHandler' and round-trips through real storage, while the reference type is refused at handler resolution with the actionable 'register a dedicated handler' exception. This replaces the contrived 'HandlerlessCore'-based enforcement test with a realistic end-to-end demonstration.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/Drupal/Tests/Driver/Unit/Core/Field/FieldShapeClassifierTest.php (1)

56-69: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing coverage for the ListDataDefinitionInterface branch.

testFieldIsComplexValue() only exercises the ComplexDataDefinitionInterface branch (via MapDataDefinition). FieldShapeClassifier::fieldIsComplexValue() also returns TRUE for ListDataDefinitionInterface properties, but that branch has no test.

Suggested addition
   public function testFieldIsComplexValue(): void {
     $classifier = new FieldShapeClassifier();

     $this->assertTrue($classifier->fieldIsComplexValue($this->storageWithProperties([
       'value' => DataDefinition::create('string'),
       'options' => MapDataDefinition::create(),
     ])));

+    // A list-typed property is also complex.
+    $this->assertTrue($classifier->fieldIsComplexValue($this->storageWithProperties([
+      'value' => DataDefinition::create('string'),
+      'items' => ListDataDefinition::create('string'),
+    ])));
+
     // Plain scalars are not complex.
     $this->assertFalse($classifier->fieldIsComplexValue($this->storageWithProperties([
       'value' => DataDefinition::create('string'),
       'format' => DataDefinition::create('string'),
     ])));
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Drupal/Tests/Driver/Unit/Core/Field/FieldShapeClassifierTest.php`
around lines 56 - 69, Add test coverage in testFieldIsComplexValue for the
ListDataDefinitionInterface path in FieldShapeClassifier::fieldIsComplexValue,
since the current assertions only verify the ComplexDataDefinitionInterface case
with MapDataDefinition. Extend the existing test to build storageWithProperties
using a list-type property definition and assert that fieldIsComplexValue
returns true for that shape, while keeping the existing scalar false case as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/Drupal/Tests/Driver/Unit/Core/Field/FieldShapeClassifierTest.php`:
- Around line 56-69: Add test coverage in testFieldIsComplexValue for the
ListDataDefinitionInterface path in FieldShapeClassifier::fieldIsComplexValue,
since the current assertions only verify the ComplexDataDefinitionInterface case
with MapDataDefinition. Extend the existing test to build storageWithProperties
using a list-type property definition and assert that fieldIsComplexValue
returns true for that shape, while keeping the existing scalar false case as-is.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6ea3170f-3159-4cab-90ac-121ad07db12c

📥 Commits

Reviewing files that changed from the base of the PR and between 8327721 and 5820918.

📒 Files selected for processing (14)
  • composer.json
  • src/Drupal/Driver/Core/Core.php
  • src/Drupal/Driver/Core/CoreInterface.php
  • src/Drupal/Driver/Core/Field/DefaultHandler.php
  • src/Drupal/Driver/Core/Field/FieldShapeClassifier.php
  • src/Drupal/Driver/Core/Field/FieldShapeClassifierInterface.php
  • src/Drupal/Driver/Core/Field/README.md
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/CustomModuleFieldKernelTest.php
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/FieldTypeCoverageKernelTest.php
  • tests/Drupal/Tests/Driver/Unit/Core/Field/FieldShapeClassifierTest.php
  • tests/fixtures/modules/driver_field_test/composer.json
  • tests/fixtures/modules/driver_field_test/driver_field_test.info.yml
  • tests/fixtures/modules/driver_field_test/src/Plugin/Field/FieldType/DriverTestReferenceItem.php
  • tests/fixtures/modules/driver_field_test/src/Plugin/Field/FieldType/DriverTestScalarItem.php
✅ Files skipped from review due to trivial changes (3)
  • tests/fixtures/modules/driver_field_test/composer.json
  • tests/fixtures/modules/driver_field_test/driver_field_test.info.yml
  • src/Drupal/Driver/Core/Field/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/Drupal/Tests/Driver/Kernel/Core/Field/FieldTypeCoverageKernelTest.php
  • src/Drupal/Driver/Core/Field/DefaultHandler.php

@AlexSkrypnyk AlexSkrypnyk merged commit 8176be0 into master Jul 7, 2026
13 checks passed
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