function VariationCache::getMultiple

Overrides VariationCacheInterface::getMultiple

File

core/lib/Drupal/Core/Cache/VariationCache.php, line 61

Class

VariationCache
Wraps a regular cache backend to make it support cache contexts.

Namespace

Drupal\Core\Cache

Code

public function getMultiple(array $items) : array {
    // This method does not use ::getRedirectChain() like ::get() does, because
    // we are looking for multiple cache entries and can therefore optimize the
    // following of redirect chains by calling ::getMultiple() on the underlying
    // cache backend.
    //
    // However, ::getRedirectChain() has an internal cache that we could both
    // benefit from and contribute to whenever we call this function. So any use
    // or manipulation of $this->redirectChainCache below is for optimization
    // purposes. A description of the internal cache structure is on the
    // property documentation of $this->redirectChainCache.
    //
    // Create a map of CIDs with their associated $items index and cache keys.
    $cid_map = [];
    foreach ($items as $index => [
        $keys,
        $cacheability,
    ]) {
        // Try to optimize based on the cached redirect chain.
        if ($chain = $this->getValidatedCachedRedirectChain($keys, $cacheability)) {
            $last_item = end($chain);
            // Immediately skip processing the CID for cache misses.
            if ($last_item === FALSE) {
                continue;
            }
            // We do not need to calculate the initial CID as its part of the chain.
            $initial_cid = array_key_first($chain);
            // Prime the CID map with the last known redirect for the initial CID.
            assert($last_item->data instanceof CacheRedirect);
            $cid = $this->createCacheIdFast($keys, $last_item->data);
        }
        else {
            $cid = $initial_cid = $this->createCacheIdFast($keys, $cacheability);
        }
        $cid_map[$cid] = [
            'index' => $index,
            'keys' => $keys,
            'initial' => $initial_cid,
        ];
    }
    // Go over all CIDs and update the map according to found redirects. If the
    // map is empty, it means we've followed all CIDs to their final result or
    // lack thereof.
    $results = [];
    while (!empty($cid_map)) {
        $new_cid_map = [];
        $fetch_cids = array_keys($cid_map);
        foreach ($this->cacheBackend
            ->getMultiple($fetch_cids) as $cid => $result) {
            $info = $cid_map[$cid];
            // Add redirects to the next CID map, so the next iteration can look
            // them all up in one ::getMultiple() call to the cache backend.
            if ($result->data instanceof CacheRedirect) {
                $redirect_cid = $this->createCacheIdFast($info['keys'], $result->data);
                $new_cid_map[$redirect_cid] = $info;
                $this->redirectChainCache[$info['initial']][$cid] = $result;
                continue;
            }
            $results[$info['index']] = $result;
        }
        // Any CID that did not get a cache hit is still in $fetch_cids. Add them
        // to the internal redirect chain cache as a miss.
        foreach ($fetch_cids as $fetch_cid) {
            $info = $cid_map[$fetch_cid];
            $this->redirectChainCache[$info['initial']][$fetch_cid] = FALSE;
        }
        $cid_map = $new_cid_map;
    }
    return $results;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.