public function VariationCache::set in VariationCache 8
Stores data in the cache.
Parameters
string[] $keys: The cache keys of the data to store.
mixed $data: The data to store in the cache.
\Drupal\Core\Cache\CacheableDependencyInterface $cacheability: The cache metadata of the data to store.
\Drupal\Core\Cache\CacheableDependencyInterface $initial_cacheability: The cache metadata of the data to store before other systems had a chance to adjust it. This is also commonly known as "pre-bubbling" cacheability.
Throws
\LogicException Thrown when cacheability is provided that does not contain a cache context or does not completely contain the initial cacheability.
Overrides VariationCacheInterface::set
See also
\Drupal\Core\Cache\CacheBackendInterface::set()
File
- src/
Cache/ VariationCache.php, line 67
Class
- VariationCache
- Wraps a regular cache backend to make it support cache contexts.
Namespace
Drupal\variationcache\CacheCode
public function set(array $keys, $data, CacheableDependencyInterface $cacheability, CacheableDependencyInterface $initial_cacheability) {
$initial_contexts = $initial_cacheability
->getCacheContexts();
$contexts = $cacheability
->getCacheContexts();
if (array_diff($initial_contexts, $contexts)) {
throw new \LogicException('The complete set of cache contexts for a variation cache item must contain all of the initial cache contexts.');
}
// Don't store uncacheable items.
if ($cacheability
->getCacheMaxAge() === 0) {
return;
}
// Track the potential effect of cache context folding on cache tags.
$folded_cacheability = CacheableMetadata::createFromObject($cacheability);
$cid = $this
->createCacheId($keys, $folded_cacheability);
// Check whether we had any cache redirects leading to the cache ID already.
// If there are none, we know that there is no proper redirect path to the
// cache ID we're trying to store the data at. This may be because there is
// either no full redirect path yet or there is one that is too specific at
// a given step of the way. In case of the former, we simply need to store a
// redirect. In case of the latter, we need to replace the overly specific
// step with a simpler one.
$chain = $this
->getRedirectChain($keys, $initial_cacheability);
if (!array_key_exists($cid, $chain)) {
// We can easily find overly specific redirects by comparing their cache
// contexts to the ones we have here. If a redirect has more or different
// contexts, it needs to be replaced with a simplified version.
//
// Simplifying overly specific redirects can be done in two ways:
//
// -------
//
// Problem: The redirect is a superset of the current cache contexts.
// Solution: We replace the redirect with the current contexts.
//
// Example: Suppose we try to store an object with context A, whereas we
// already have a redirect that uses A and B. In this case we simply store
// the object at the address designated by context A and next time someone
// tries to load the initial AB object, it will restore its redirect path
// by adding an AB redirect step after A.
//
// -------
//
// Problem: The redirect overlaps, with both options having unique values.
// Solution: Find the common contexts and use those for a new redirect.
//
// Example: Suppose we try to store an object with contexts A and C, but
// we already have a redirect that uses A and B. In this case we find A to
// be the common cache context and replace the redirect with one only
// using A, immediately followed by one for AC so there is a full path to
// the data we're trying to set. Next time someone tries to load the
// initial AB object, it will restore its redirect path by adding an AB
// redirect step after A.
foreach ($chain as $chain_cid => $result) {
if ($result && $result->data instanceof CacheRedirect) {
$result_contexts = $result->data
->getCacheContexts();
if (array_diff($result_contexts, $contexts)) {
// Check whether we have an overlap scenario as we need to manually
// create an extra redirect in that case.
$common_contexts = array_intersect($result_contexts, $contexts);
if ($common_contexts != $contexts) {
// Set the redirect to the common contexts at the current address.
// In the above example this is essentially overwriting the
// redirect to AB with a redirect to A.
$common_cacheability = (new CacheableMetadata())
->setCacheContexts($common_contexts);
$this->cacheBackend
->set($chain_cid, new CacheRedirect($common_cacheability));
// Before breaking the loop, set the current address to the next
// one in line so that we can store the full redirect as well. In
// the above example, this is the part where we immediately also
// store a redirect to AC at the CID that A pointed to.
$chain_cid = $this
->createCacheIdFast($keys, $common_cacheability);
}
break;
}
}
}
// The loop above either broke at an overly specific step or completed
// without any problem. In both cases, $chain_cid ended up with the value
// that we should store the new redirect at.
//
// Cache redirects are stored indefinitely and without tags as they never
// need to be cleared. If they ever end up leading to a stale cache item
// that now uses different contexts then said item will either follow an
// existing path of redirects or carve its own over the old one.
$this->cacheBackend
->set($chain_cid, new CacheRedirect($cacheability));
}
$this->cacheBackend
->set($cid, $data, $this
->maxAgeToExpire($cacheability
->getCacheMaxAge()), $folded_cacheability
->getCacheTags());
}