How do I create a cache context in Drupal 8 that varies on user/node field data? 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:


The node was created by the logged in user, or:
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!
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/8.1.x)

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/8.1.x for an example of a cache context, which itself depends on other data, which can be invalidated.