Problem/Motivation
On a node page, a prop bound to a field of a referenced node resolves against the route's node. The source chain is "[Entity] ➜ Referenced [Entity]" on an entity reference field, then "[Entity] ➜ [Field]" and a field property.
Display Builder's entity view passes view_mode, entity and display plus every global runtime context, including @node.node_route_context:node (EntityViewDisplayTrait::getContextsForEntity()). EntityReferencedDerivableContext::getDerivedContexts() removes entity from these contexts and appends the referenced entity as entity with array_merge(). The route's node now comes before it. The next step takes the first context that matches each definition, in DerivableContextPluginBase::setDefinedContextValues():
$matching_context = \reset($matches);
Both nodes match the entity:node definition, so reset() returns the route's node. That node has no such field, the value is NULL, and a required prop throws on render:
Drupal\Core\Render\Component\Exception\InvalidComponentException: [hda_theme:progress_bar/current] The property current is required.
The same page renders a video through a Media reference correctly, because the global contexts hold no Media entity. A reference to a user entity would meet @user.current_user_context:current_user first by the same order; we have not tested that.
In drush, without a route, the same source configuration returns the referenced node's value.
Steps to reproduce
- Install Drupal 11.4.7, UI Patterns 2.0.21 and Display Builder 1.0.0-beta7 with
display_builder_entity_view. - Create a content type Campaign with an integer field
field_anteile_current, and a content type Page with an entity reference fieldfield_campaignthat targets Campaign. - Add a component with a required integer prop
current. - Enable Display Builder with overrides on the Page view display. On a Page node, place the component and bind
currentto "[Entity] ➜ Referenced [Entity]" onfield_campaign, then "[Entity] ➜ [Field]"field_anteile_current, property value. - Publish and open the Page node. The request fails with the exception above.
Proposed resolution
Prefer the context whose key equals the definition name, and fall back to the first match:
- $matching_context = \reset($matches);
+ // Prefer the context with the definition's own name, so a derived
+ // 'entity' wins over another context of the same entity type, such as
+ // the route's node.
+ $matching_context = $matches[$name] ?? \reset($matches);
EntityReferencedDerivableContext keys the referenced entity as entity, the same name as the entity context definition of the next step, so the referenced node wins.
We run this as a local patch on 2.0.21. The prop renders the Campaign's value (520000 of 800000), and the other bindings on the page render as before: the title, the video through the Media reference, and field formatters.
SourcePluginBase::setDefinedContextValues() selects only through context_mapping, so the order of contexts does not affect it.
Remaining tasks
- Add a kernel test with a node that references another node, rendered with a node route context.
- Open a merge request against 2.0.x.
User interface changes
None.
API changes
None.
Data model changes
None.
Issue fork ui_patterns-3626950
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
just_like_good_vibeshello,
thank you for reporting that issue. let’s fix that asap.
Comment #3
just_like_good_vibeslet’s follow your suggestions and also let’s carry a little other investigation in where exactly do we also merge contexts and if that would help to set an overriden context as being the first candidate to a reset function instead of being the last selected one despite being the freshest one. i mean your issue raised the question of context selection priority when multiple matches.
elsewhere in the code, were already played a lot with context keys (to fill the gap with existing core code in terms of context matching), and the spirit of your proposed fix makes perfect sense.
Comment #4
anruetherComment #7
just_like_good_vibes