Information about the Drupal Cache API

Basics

Note: If not specified, all of the methods mentioned here belong to \Drupal\Core\Cache\CacheBackendInterface.

The Cache API is used to store data that takes a long time to compute. Caching can be permanent, temporary, or valid for a certain timespan, and the cache can contain any type of data.

To use the Cache API:

  • Request a cache object through \Drupal::cache() or by injecting a cache service.
  • Define a Cache ID (cid) value for your data. A cid is a string, which must contain enough information to uniquely identify the data. For example, if your data contains translated strings, then your cid value must include the interface text language selected for page.
  • Call the get() method to attempt a cache read, to see if the cache already contains your data.
  • If your data is not already in the cache, compute it and add it to the cache using the set() method. The third argument of set() can be used to control the lifetime of your cache item.

Example:

$cid = 'mymodule_example:' . \Drupal::languageManager()->getCurrentLanguage()->getId();

$data = NULL;
if ($cache = \Drupal::cache()->get($cid)) {
  $data = $cache->data;
}
else {
  $data = my_module_complicated_calculation();
  \Drupal::cache()->set($cid, $data);
}

Note the use of $data and $cache->data in the above example. Calls to \Drupal::cache()->get() return a record that contains the information stored by \Drupal::cache()->set() in the data property as well as additional meta information about the cached data. In order to make use of the cached data you can access it via $cache->data.

Cache bins

Cache storage is separated into "bins", each containing various cache items. Each bin can be configured separately; see Configuration.

When you request a cache object, you can specify the bin name in your call to \Drupal::cache(). Alternatively, you can request a bin by getting service "cache.nameofbin" from the container. The default bin is called "default", with service name "cache.default", it is used to store common and frequently used caches.

Other common cache bins are the following:

  • bootstrap: Small caches needed for the bootstrap on every request.
  • render: Contains cached HTML strings like cached pages and blocks, can grow to large size.
  • data: Contains data that can vary by path or similar context.
  • discovery: Contains cached discovery data for things such as plugins, views_data, or YAML discovered data such as library info.

A module can define a cache bin by defining a service in its modulename.services.yml file as follows (substituting the desired name for "nameofbin"):

cache.nameofbin:
  class: Drupal\Core\Cache\CacheBackendInterface
  tags:
    - { name: cache.bin }
  factory_method: get
  factory_service: cache_factory
  arguments: [nameofbin]

See the Services topic for more on defining services.

Deletion

There are two ways to remove an item from the cache:

  • Deletion (using delete(), deleteMultiple() or deleteAll()) permanently removes the item from the cache.
  • Invalidation (using invalidate(), invalidateMultiple() or invalidateAll()) is a "soft" delete that only marks items as "invalid", meaning "not fresh" or "not fresh enough". Invalid items are not usually returned from the cache, so in most ways they behave as if they have been deleted. However, it is possible to retrieve invalid items, if they have not yet been permanently removed by the garbage collector, by passing TRUE as the second argument for get($cid, $allow_invalid).

Use deletion if a cache item is no longer useful; for instance, if the item contains references to data that has been deleted. Use invalidation if the cached item may still be useful to some callers until it has been updated with fresh data. The fact that it was fresh a short while ago may often be sufficient.

Invalidation is particularly useful to protect against stampedes. Rather than having multiple concurrent requests updating the same cache item when it expires or is deleted, there can be one request updating the cache, while the other requests can proceed using the stale value. As soon as the cache item has been updated, all future requests will use the updated value.

Cache Tags

The fourth argument of the set() method can be used to specify cache tags, which are used to identify which data is included in each cache item. A cache item can have multiple cache tags (an array of cache tags), and each cache tag is a string. The convention is to generate cache tags of the form [prefix]:[suffix]. Usually, you'll want to associate the cache tags of entities, or entity listings. You won't have to manually construct cache tags for them — just get their cache tags via \Drupal\Core\Entity\EntityInterface::getCacheTags() and \Drupal\Core\Entity\EntityTypeInterface::getListCacheTags(). Data that has been tagged can be invalidated as a group: no matter the Cache ID (cid) of the cache item, no matter in which cache bin a cache item lives; as long as it is tagged with a certain cache tag, it will be invalidated.

Because of that, cache tags are a solution to the cache invalidation problem:

  • For caching to be effective, each cache item must only be invalidated when absolutely necessary. (i.e. maximizing the cache hit ratio.)
  • For caching to be correct, each cache item that depends on a certain thing must be invalidated whenever that certain thing is modified.

A typical scenario: a user has modified a node that appears in two views, three blocks and on twelve pages. Without cache tags, we couldn't possibly know which cache items to invalidate, so we'd have to invalidate everything: we had to sacrifice effectiveness to achieve correctness. With cache tags, we can have both.

Example:

// A cache item with nodes, users, and some custom module data.
$tags = array(
  'my_custom_tag',
  'node:1',
  'node:3',
  'user:7',
);
\Drupal::cache()->set($cid, $data, CacheBackendInterface::CACHE_PERMANENT, $tags);

// Invalidate all cache items with certain tags.
\Drupal\Core\Cache\Cache::invalidateTags(array('user:1'));

Drupal is a content management system, so naturally you want changes to your content to be reflected everywhere, immediately. That's why we made sure that every entity type in Drupal 8 automatically has support for cache tags: when you save an entity, you can be sure that the cache items that have the corresponding cache tags will be invalidated. This also is the case when you define your own entity types: you'll get the exact same cache tag invalidation as any of the built-in entity types, with the ability to override any of the default behavior if needed. See \Drupal\Core\Entity\EntityInterface::getCacheTags(), \Drupal\Core\Entity\EntityTypeInterface::getListCacheTags(), \Drupal\Core\Entity\Entity::invalidateTagsOnSave() and \Drupal\Core\Entity\Entity::invalidateTagsOnDelete().

Configuration

By default cached data is stored in the database. This can be configured though so that all cached data, or that of an individual cache bin, uses a different cache backend, such as APC or Memcache, for storage.

In a settings.php file, you can override the service used for a particular cache bin. For example, if your service implementation of \Drupal\Core\Cache\CacheBackendInterface was called cache.custom, the following line would make Drupal use it for the 'cache_render' bin:

 $settings['cache']['bins']['render'] = 'cache.custom';

Additionally, you can register your cache implementation to be used by default for all cache bins with:

 $settings['cache']['default'] = 'cache.custom';

See also

https://www.drupal.org/node/1884796

File

core/modules/system/core.api.php, line 367
Documentation landing page and topics, plus core library hooks.

Functions

Namesort descending Location Description
Drupal::cache core/lib/Drupal.php Returns the requested cache bin.

Classes

Namesort descending Location Description
Cache core/lib/Drupal/Core/Cache/Cache.php Helper methods for cache.
CacheableMetadata core/lib/Drupal/Core/Cache/CacheableMetadata.php Defines a generic class for passing cacheability metadata.
CacheCollector core/lib/Drupal/Core/Cache/CacheCollector.php Default implementation for CacheCollectorInterface.
ChainedFastBackend core/lib/Drupal/Core/Cache/ChainedFastBackend.php Defines a backend with a fast and a consistent backend chain.
DatabaseBackend core/lib/Drupal/Core/Cache/DatabaseBackend.php Defines a default cache implementation.
MemoryBackend core/lib/Drupal/Core/Cache/MemoryBackend.php Defines a memory cache implementation.
NullBackend core/lib/Drupal/Core/Cache/NullBackend.php Defines a stub cache implementation.
PhpBackend core/lib/Drupal/Core/Cache/PhpBackend.php Defines a PHP cache implementation.

Interfaces

Namesort descending Location Description
CacheableDependencyInterface core/lib/Drupal/Core/Cache/CacheableDependencyInterface.php Defines an interface for objects which may be used by other cached objects.
CacheBackendInterface core/lib/Drupal/Core/Cache/CacheBackendInterface.php Defines an interface for cache implementations.
CacheCollectorInterface core/lib/Drupal/Core/Cache/CacheCollectorInterface.php Provides a caching wrapper to be used in place of large structures.
CacheTagsChecksumInterface core/lib/Drupal/Core/Cache/CacheTagsChecksumInterface.php Provides checksums for cache tag invalidations.
CacheTagsInvalidatorInterface core/lib/Drupal/Core/Cache/CacheTagsInvalidatorInterface.php Defines required methods for classes wanting to handle cache tag changes.

Comments

\Drupal\Core\Cache\Cache::deleteTags(array('node' => array(1));

should be:

\Drupal\Core\Cache\Cache::deleteTags(array('node' => array(1)));

Kind regards,

Thomas Dik

According to change record https://www.drupal.org/node/2344683 cache tags must now be strings. As a result:

<?php
// A cache item with nodes, users, and some custom module data.
$tags = array(
 
'my_custom_tag' => TRUE,
 
'node' => array(1, 3),
 
'user' => array(7),
);
?>

Should probably be:

<?php
$tags
= array(
 
'my_custom_tag',
 
'node:1',
 
'node:3',
 
'user:7',
);
?>