Evaluate 'property paths' as an alternative syntax to prop expressions

Created on 11 August 2024, 5 months ago
Updated 12 August 2024, 5 months ago

Overview

In order to resolve prop values from entities and fields, we have the concept of prop expressions. Most of this is new work that introduces new concepts.

However there are existing implementations of something similar in contrib, namely in Search API module and GraphQL module.

Search API

When creating an index in Search API you can add fields to the entity. The available fields depend on the data source for the index. In most cases the datasource is an entity. As a result the fields available are limited to those that can be resolved from the entity. You can however traverse into reference entities. For example, consider the standard install profile's data model. There is a tags field on the article content type that allows referencing terms from the tags vocabulary. There is an image field on the article content type that allows adding an image file entity. When creating the index, you can add fields from referenced entities. Here's a screenshot showing indexing the username of the revision user, from the tag term, in the tags field on the node. The screenshot also shows referencing the file URL from the file entity in the image field.

Search API stores this as a property path in the exported index config. Here's a sample property path for the tag example above
field_tags:entity:revision_user:entity:name

To resolve these values at index time, the fields helper service is used.

Graph QL

GraphQL has a similar concept. When building a query resolver for GraphQL you make use of various builder and producer plugins.
Each of those has a current context, which might be an entity. From there you combine builders and producers to resolve a value for a given query key. One such producer plugin is the PropertyPath producer.

This makes use of the typed data module's \Drupal\typed_data\DataFetcherInterface::fetchDataByPropertyPath method.

Proposed resolution

Explore prior art in the contrib ecosystem and attempt to re-use an proven existing approach rather than reinvent a new system.

User interface changes

📌 Task
Status

Postponed: needs info

Component

Data model

Created by

🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @larowlan
  • Status changed to Postponed: needs info 5 months ago
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Thanks, I definitely did not know about either of these!

    1. field_tags:entity:revision_user:entity:name → this expression can only be evaluated on a given entity type+bundle context. Because not every entity type + bundle has a field_tags. That's why this is insufficient.
    2. In that PropertyPath producer, the root_type is optional, which causes the same problem as the above. That seems possible to overcome though! Plus, I quite like the @DataProducer concept — that means the data could be produced using external data sources too.

      TIL the module exists. The fetchDataByPropertyPath() method indeed seems very similar. Test coverage seems thin, but that can be overcome.

    There are three requirements neither of those meet:

    1. the stored expression/property path must define what the expected root type is. XB's \Drupal\experience_builder\PropExpressions\StructuredData\Evaluator specifically checks StructuredDataPropExpressionInterface::isSupported() for this. Otherwise an expression cannot be evaluated in isolation. (Plus, this is used by ValidComponentTreeConstraintValidator(), too.)

      the code you linked from the GraphQL ecosystem could quite easily be updated to meet this one)

    2. the ability to compactly represent fetching multiple field prop values from a field.

      XB's PropExpression:

      ℹ︎␜entity:node:article␝field_image␞␟{src↝entity␜␜entity:file␝uri␞␟value,width↠width,height↠height,alt↠alt}
      

      That single expression would require the following multiple property paths:

      entity:node:article.field_image.src.entity:file.uri.value
      entity:node:article.field_image.width
      entity:node:article.field_image.height
      entity:node:article.field_image.alt
      

      (although AFAICT that does not yet support entity:node:article in the expressions, or if it does, then there's no test coverage for it)

    3. the ability to also describe the shape of the resulting data — in the above example entity:node:article.field_image.src.entity:file.uri.value would be the correct property path to retrieve a value from, but it doesn't yet capture the expected name/key is src

    Preliminary conclusion

    There is some prior art, but it does not do everything PropExpressions do. I'm working to capture that at 📌 Document the current JSON-based data model, and describe in an ADR Active .

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    FWIW search api overcomes these issues using data source plugins, you can index multiple bundles (and even multiple entity types) to the same index. Each field is a combination of property path and data source id. That gives you the root data type. Fields helper even has a filter by data source method which is similar to the isSupported

    I concede that the multiple properties syntax is more verbose

Production build 0.71.5 2024