5

Let's say I have a complex render array that has two variations that depend on a simple if: whether the logged in user can edit a node inside it. There are two scenarios I look for:

  1. The node was created by the logged in user, or:
  2. The node's field_group (entity reference) matches the logged in user's field_group.

These two conditions are independent of roles/permissions so I can't fall back on those contexts. Originally, I simply used the "user" context but this would create far too much variation and potentially lead to a very large database table (not to mention it was inefficient to have to cache this again for every user).

I imagine I would need to create a context like: "caneditnode:nid" and somehow pass nid to a handler that would load the Node to check its fields and owner and compare to the data in Drupal::currentUser(). Is that possible? How would I go about doing this? Thanks!

1
  • I would check is the user is authehticated. You don't have to worry about the "potentially lead to a very large database table". There is already a ***load of data so concerning yourself with this is pointless.
    – user21641
    Commented Jul 19, 2017 at 3:40

2 Answers 2

3

You can add a cache key for the two scenarios

$build['#cache']['keys'][] = $canedit ? 'caneditnode' : 'cannoteditnode';

and build the complex render array in a #pre_render callback. See https://dev.acquia.com/blog/drupal-8-performance-render-caching

2
  • :facepalm: I didn't realize I could use keys this way! Thank you! Drupal is awesome~ Commented Jul 19, 2017 at 13:22
  • There are a number of limitiations with this. Where exactly are you adding this? Are you adding something to the node with hook_node_view() or a similar function or is this your own render array?
    – Berdir
    Commented Jul 19, 2017 at 13:48
9

A cache key is not the right solution as dynamic_page_cache won't vary on the right things.

What you do is:

You create a custom cache context (see core.services.yml for many examples), which itself is dependent on the [route] and [user] cache context (as it needs to check the node).

e.g. cookies:[cookie_name] is a good example. (https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Cache%21Context%21CookiesCacheContext.php/class/CookiesCacheContext)

In that way you can have indeed a:

caneditnode:[entity_id]

Whenever this cache context is used, your handler is checked and needs to return the right information based on the given Context.

If caneditnode is given as cache context without context it could just throw an Exception or fallback to ['user', 'route'] as that is what it depends on.

In getCacheableMetadata you would just return the node cacheable metadata and the user.roles.

See https://api.drupal.org/api/drupal/core%21core.services.yml/service/cache_context.user.permissions for an example of a cache context, which itself depends on other data, which can be invalidated.

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.