0

I have a custom entity that I've added some computed fields to, so the classes involved are:

  • class MyEntity extends ContentEntityBase
  • class ComputedFieldA extends FieldItemList
  • class ComputedFieldB extends FieldItemList

My issue is that I want the computed fields to either not be cached at all, or to be cached but with a different invalidation strategy.

Is what I want possible? Or do I just need to invalidate cache for the whole entity?

Edit: The custom field itself is basically a count of the rows in another database table. I want that count to be cached separately then invalidated if new rows are inserted.

The output is being consumed via the default jsonapi endpoint for the entity.

Edit 2: I guess this is more complex than I thought so I'll describe the entities in more detail:

Entity A:

  • Has a 1:1 relationship with nodes based on UUID
  • Has a count of Entity B entities that are related to the node (computed)
  • Has a calculation based on that count (computed)

Entity B:

  • Has an N:1 relationship with nodes based on NID

So, if a new Entity B is created for node X then I want the cache invalidated on the two computed fields of Entity A for node XXXX-XXXX-XXXX-XXXX so that the jsonapi endpoint shows up to date computed data.

If I can add a cache tag of node:X to each instance of the computed field I expect that would achieve what I want.

8
  • The edit is more like a new question. Is this other database table also an entity table? If yes, you can use the CRUD hooks of that entity to invalidate this entity or you could add the entity tag of the other entity to the field to have it invalidated automatically on CRUD operations. If no, you have to implement something similar yourself.
    – 4uk4
    Commented Apr 6, 2022 at 19:05
  • Edit 2: If this is about different content types the new bundle list tag might be helpful. See drupal.org/node/3107058
    – 4uk4
    Commented Apr 6, 2022 at 19:46
  • No it's not about different content types. Entity A and Entity B are pure custom single table entities, but Entity A has a uuid field that refers to a specific node and Entity B has a nid field that refers to the same node.
    – Lambic
    Commented Apr 6, 2022 at 19:56
  • OK, then use the tag entity_b_list.
    – 4uk4
    Commented Apr 6, 2022 at 20:00
  • That would probably work, but I'm not sure where I add that tag. In the entity definition? The FieldItemList implementation? Somewhere else?
    – Lambic
    Commented Apr 6, 2022 at 20:04

1 Answer 1

3

I doesn't matter whether the field is computed. Caching depends on how the field is rendered in the field formatter. Cache metadata added to the render array bubbles up and is merged with that of the other fields and the entity.

Fields by default are not cached on their own, but you can change this. If the field needs a different caching strategy, add cache keys, and the rendered field can be shared between fields in other entity instances rendering with the same cache keys. If the field is highly dynamic then add a lazy builder and make sure it gets placeholdered, either automatically or by setting #create_placeholder.

Edit 2:

The entity class could add a cache list tag for the entity b:

class MyEntity extends ContentEntityBase {

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    $cache_tags = parent::getCacheTags();
    $cache_tags[] = 'entity_b_list';
    return $cache_tags;
  }
2
  • So it sounds like I need to define my own field formatters for the fields I want special caching on? Does it matter that I'm consuming the end result via jsonapi?
    – Lambic
    Commented Apr 6, 2022 at 18:35
  • Then define a FieldNormalizer with protected $supportedInterfaceOrClass = ComputedFieldA::class;
    – 4uk4
    Commented Apr 6, 2022 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.