Repository navigation
Drupal entity fields - #564
Open
giuseppe-esposito-87 wants to merge 11 commits into
Open
giuseppe-esposito-87 wants to merge 11 commits into
giuseppe-esposito-87 wants to merge 11 commits into
Conversation
Drupal content entities read their fields and any other stored value through ContentEntityBase::__get(), but the interfaces they are typed with (NodeInterface, ContentEntityInterface) declare no __get(), so every field read on them was reported as an unknown property. In a Drupal project, interfaces that extend FieldableEntityInterface now get the same untyped __get() the class has, so a read on them is mixed, as on the class. Interfaces without fields keep reporting unknown properties. Also adds the mapping from a fieldable receiver to the entity types it may hold, which the field readers build on. Assisted-by: claude-code/claude-opus-5-5
A property a framework stores through __set(), such as a Drupal entity field, now counts as a magic write: assigning to it no longer narrows a later read to the assigned value, since the setter stores the value into the field and the read keeps the field's type. Properties declared by @Property tags still narrow as before. Assisted-by: claude-code/claude-opus-5-5
The entity type reader now also keeps the entity_keys and revision_metadata_keys a declaration writes, whether it is translatable, and whether it is a content entity type, from attributes and from annotations alike. Annotation values written as bare words, such as translatable = TRUE, are now read too. Assisted-by: claude-code/claude-opus-5-5
The plugin index now keeps the list_class a field type's attribute or annotation names, so a field's item list class can be found from its field type. Assisted-by: claude-code/claude-opus-5-5
The base fields an entity class's baseFieldDefinitions() declares are now typed properties of the class and of the interfaces it implements: $node->title is a FieldItemList<StringItem>, and a reference field such as $node->uid also names the class of the entity type it points to. Fields taken from the parent class and from core's owner, published and revision log helpers count, under the names the entity type's keys give them, as do the boolean fields Drupal's entity field manager adds itself. An interface several entity classes implement has the fields all of them have. The names complete after ->, go-to-definition lands on the line that declares the field, and writing to a field keeps its type. Editing an entity class or a field type refreshes the fields everywhere they show. Assisted-by: claude-code/claude-opus-5-5
The fields that field storage files declare are now typed properties of their entity type's class and interfaces, like base fields: $node->field_tags is an EntityReferenceFieldItemList<EntityReferenceItem> that names Term. Field storage files count in extensions' config/install and config/optional, core's profiles included, and anywhere else in the project outside vendor, core and contrib, recipes, and tests, which covers config/sync and config split folders; a test module's file counts while it is open. A field declared by several files is one field, typed by all of them, and go-to-definition lists every file. Adding, editing, or deleting a field storage file refreshes the fields everywhere they show. Assisted-by: claude-code/claude-opus-5-5
The symbol map now keeps what a field item class's propertyDefinitions() declares: each property it adds to the array it returns, with the data type its definition creates, the properties it unsets, and whether it takes its parent's. Assisted-by: claude-code/claude-opus-5-5
A field item class now has the properties its propertyDefinitions() declares, with those it takes from its parent's and without those it unsets, and a field reads them on its first item, as Drupal's item lists do: $node->body->format and $node->field_tags->target_id complete and resolve. A reference field's entity property is its target class, nullable since an empty field gives null, or any entity when the field names no target, on the list and on its items alike, and referencedEntities() gives the target class too. A language property is a nullable language, and every stored value stays mixed. Writing a property keeps its type. Editing an item class's propertyDefinitions() refreshes its properties on the item, the classes that extend it, and the fields that hold it. Assisted-by: claude-code/claude-opus-5-5
Assisted-by: claude-code/claude-opus-5-5
A field name passed to a fieldable entity's get(), set(), hasField() and getFieldDefinition() completes, goes to its declaration, shows its field type on hover, and finds its references, the property reads included. get() with a known field name is typed like reading the field as a property. Assisted-by: claude-code/claude-opus-5-5
Files the follow-ups: fields added by hooks, warnings for unknown field names, and field names in entity queries. Assisted-by: claude-code/claude-opus-5-5
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds DR4: a Drupal content entity's fields are typed properties of the entity and of its interfaces, and their names complete and navigate.
baseFieldDefinitions(), with the fields core adds from the entity keys and from the owner, published and revision log traits.field.storage.*.ymlfiles in modules, profiles and the site's exported configuration (config/syncbeside the web root).value,target_id,entity, …).entityis typed as the class of the entity type the field points to; stored values staymixed.get(),set(),hasField()andgetFieldDefinition()completes, goes to its declaration, shows its field type on hover and finds its references, property reads included.get('title')is typed like->title.mixed, as it is on the entity class. On Drupal core 11.4 this removes about 640 false reports.Three follow-ups are filed in the roadmap: fields added by hooks (DR29), a warning for unknown field names (DR30), and field names in entity queries (DR31).
How to test: run
composer installinexamples/drupal, openexamples/drupalwith this branch's build, then openweb/modules/custom/acme/src/NoteSummary.php:$note->to seetitle,id,uidandfield_tags. Go to the definition oftitle(it lands inNote.php) and offield_tags(it lands inconfig/sync/field.storage.acme_note.field_tags.yml).$tagsand$firstTagto see theTermentity reference list and?Term.isTagged(), complete insidehasField(''), and find the references of'field_tags': they include the$note->field_tagsreads.Checklist
If applicable:
CHANGELOG.mdREADME.md,docs/,examples/)config-schema.json). Not applicable: this PR adds or changes no setting.the changes and why they are needed.
the changelog, and other user-facing content, and removed or corrected
anything inaccurate, unclear, or unnecessary.