You are here

public function CacheContextsManager::optimizeTokens in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php \Drupal\Core\Cache\Context\CacheContextsManager::optimizeTokens()

Optimizes cache context tokens (the minimal representative subset).

A minimal representative subset means that any cache context token in the given set of cache context tokens that is a property of another cache context cache context token in the set, is removed.

Hence a minimal representative subset is the most compact representation possible of a set of cache context tokens, that still captures the entire universe of variations.

If a cache context is being optimized away, it is able to set cacheable metadata for itself which will be bubbled up.

For example, when caching per user ('user'), also caching per role ('user.roles') is meaningless because "per role" is implied by "per user".

In the following examples, remember that the period indicates hierarchy and the colon can be used to get a specific value of a calculated cache context:

  • ['a', 'a.b'] -> ['a']
  • ['a', 'a.b.c'] -> ['a']
  • ['a.b', 'a.b.c'] -> ['a.b']
  • ['a', 'a.b', 'a.b.c'] -> ['a']
  • ['x', 'x:foo'] -> ['x']
  • ['a', 'a.b.c:bar'] -> ['a']

Parameters

string[] $context_tokens: A set of cache context tokens.

Return value

string[] A representative subset of the given set of cache context tokens..

1 call to CacheContextsManager::optimizeTokens()
CacheContextsManager::convertTokensToKeys in core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php
Converts cache context tokens to cache keys.

File

core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php, line 159

Class

CacheContextsManager
Converts cache context tokens into cache keys.

Namespace

Drupal\Core\Cache\Context

Code

public function optimizeTokens(array $context_tokens) {
  $optimized_content_tokens = [];
  foreach ($context_tokens as $context_token) {

    // Extract the parameter if available.
    $parameter = NULL;
    $context_id = $context_token;
    if (strpos($context_token, ':') !== FALSE) {
      list($context_id, $parameter) = explode(':', $context_token);
    }

    // Context tokens without:
    // - a period means they don't have a parent
    // - a colon means they're not a specific value of a cache context
    // hence no optimizations are possible.
    if (strpos($context_token, '.') === FALSE && strpos($context_token, ':') === FALSE) {
      $optimized_content_tokens[] = $context_token;
    }
    elseif ($this
      ->getService($context_id)
      ->getCacheableMetadata($parameter)
      ->getCacheMaxAge() === 0) {
      $optimized_content_tokens[] = $context_token;
    }
    else {
      $ancestor_found = FALSE;

      // Treat a colon like a period, that allows us to consider 'a' the
      // ancestor of 'a:foo', without any additional code for the colon.
      $ancestor = str_replace(':', '.', $context_token);
      do {
        $ancestor = substr($ancestor, 0, strrpos($ancestor, '.'));
        if (in_array($ancestor, $context_tokens)) {

          // An ancestor cache context is in $context_tokens, hence this cache
          // context is implied.
          $ancestor_found = TRUE;
        }
      } while (!$ancestor_found && strpos($ancestor, '.') !== FALSE);
      if (!$ancestor_found) {
        $optimized_content_tokens[] = $context_token;
      }
    }
  }
  return $optimized_content_tokens;
}