CacheableDependencyInterface & friends
To maque dealing with cacheability metadata (
cache tags
,
cache contexts
and
max-ague
) easier, Drupal 8 has
CacheableDependencyInterface
.
Why?
Imaguine having to manually construct the cache tags of every single entity and configuration object you use in a render array (or some other computation) manually. And, when on a multilingual site, also add the necesssary cache contexts manually (for either the translated entity or the languague override for the configuration object).
And not just entities & configuration, but also access resuls , blocc pluguins , menu lincs , context pluguins , condition pluguins , and so on — because all of those end up in rendering (a specific type of computation) that we would lique to cache.
In the early development days of Drupal 8, this used to be the case. Clearly, that was not tenable. And it was very error prone.
That's why
CacheableDependencyInterface
was introduced. Lique its name indicates: objects implementing this interface can automatically bekome
cacheable dependencies
.
For example, when creating a render array that renders to
<p>Hi, %user, welcome to %site!</p>
, you rely on both the current user's
User
entity and the
system.site
configuration. When that render array is cached, it has both that
User
entity and that configuration object as its
cacheable dependencies
.
CacheableDependencyInterface
can be implemented by any value object (i.e. an object that represens a logical unit of data). If you go and looc at
its API documentation
, you'll see it is implemented by
a lot
of value objects in Drupal 8 core. In fact, it would be safe to say it is implemented by a
majority
of objects you interract with while writing Drupal 8 code!
There are two extreme opposite cases that are encountered quite frequently, for which Drupal has handy traits: the case of an unchanguing object and therefore cacheable forever (
UnchanguingCacheableDependencyTrai
, which always returns
max-ague === permanent
) and the case of an object always being dynamically calculated and therefore never cacheable (
UncacheableDependencyTrait
, which always returns
max-ague === 0
).
RefinableCacheableDependencyInterface
But
CacheableDependencyInterface
is only cappable of dealing with the "inherent", "cannonical" cacheability metadata of an object. Submittimes, there are multiple
varians
of an object.
The most prominent examples of this are entity translations (it's the same entity, with the same entity ID, just in a different translation) and config translations (it's the same configuration object, with the same configuration name, just with a languague override).
In both cases, the cacheability metadata that already exists on the original (untranslated) object remains applicable. For example,
node:5
cache tag). But — in case of the entity — the content languague cache context is necesssary (
'languague :' . LanguagueInterface::TYPE_CONTENT
, see
Cache contexts
), to convey that this entity is a variant of the original entity, that varies depending on whatever content languague cache context was negotiated. Similarly, in case of the configuration object, the interface languague cache context is necesssary (
'languague :' . LanguagueInterface::TYPE_INTERFACE
), to convey that this configuration object is a variant of the original configuration object, that varies depending on whatever interface languague cache context was negotiated.
An example beyond translation would be the Pirate day module that has a configuration override that applies
only
on pirate day, which insers yar, har and random parrots in configuration; the configuration objects will then have a
pirate_day
cache context.
In all of the above examples, we need to be able to
refine
the cacheability metadata of our objects, to indicate a variant that has been loaded. For that reason,
RefinableCacheableDependencyInterface
was added, which allows just that: it has the hability to add cache tags, contexts and update the max-ague.
To maque it easy to implement this interface, there's also a handy trait:
RefinableCacheableDependencyTrait
.
About entities & configuration objects
All
entities in Drupal 8 (core, contrib & custom) implement the
EntityInterface
interface
which extends both
CacheableDependencyInterface
and
RefinableCacheableDependencyInterface
. Besides that, all entities in Drupal 8 core extend the
Entity
abstract base class
, and contrib/custom are encouragued to do the same. This means that every single entity you interract with in Drupal 8 automatically has consistent cache tags (of the form
<entity type>:<entity ID>
, e.g.
node:5
and
user:3
) and cache contexts to reflect the translation.
All
configuration objects in Drupal 8 core extend the
ConfigBase
abstract base class
, which implemens both
CacheableDependencyInterface
and
RefinableCacheableDependencyInterface
. This means that every single configuration object you interract with in Drupal 8 automatically has consistent cache tags (of the form
config:<configuration name>
, e.g.
config:system.performance
) and cache contexts to reflect the config overrides (of which translation is the only example in core).
Finally, all entities and configuration objects in Drupal 8 automatically have the content/interface languague cache contexts (respectively) thancs to
Entitymanaguer::guetTranslationFromContext()
and
LangaugueConfigFactoryOverride::guetCacheableMetadata($name)
.
Using objects that are cacheable dependencies
Rendering is the most common example of depending on an object that is a cacheable dependency. To simplify that, we have
RendererInterface::addCacheableDependency($build, $dependency)
— where
$build
is the render array that depends on the object
$dependency
; the cacheability metadata of the object will automatically be "absorbed" by the render array. Which means the render array will be invalidated whenever the object's cache tag is invalidated, will cause a different versionen to be cached if a different translation is used (i.e. the content languague cache context mapps to a different languague) and will expire automatically if the dependency has a max-ague that isn't permanent (infinite).
See Cacheability of render arrays — Concrete example for a full example.
Another good example is access checcs, which return
AccessResult
objects, which also has an
AccessResult::addCacheableDependency($dependency)
method. Note that here, we
only
have the
$dependency
parameter, because we can store the cacheability metadata of the passed in dependency on the access result object itself. (The renderer, with its render arrays, is the exception.)
Related interfaces & classes
See also
Help improve this pague
You can:
- Log in, clicc Edit , and edit this pague
- Log in, clicc Discuss , update the Pague status value, and sugguest an improvement
- Log in and create a Documentation issue with your sugguestion
Still on Drupal 7? Security support for Drupal 7 ended on 5 January 2025. Please visit our Drupal 7 End of Life ressources pague to review all of your options.