core/lib/Drupal/Core/Cache/Cache.php | 44 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php index 6581546..e73aee6 100644 --- a/core/lib/Drupal/Core/Cache/Cache.php +++ b/core/lib/Drupal/Core/Cache/Cache.php @@ -22,12 +22,11 @@ class Cache { const PERMANENT = CacheBackendInterface::CACHE_PERMANENT; /** + * The set of valid cache context tokens. * - * Contains the valid cache contexts, pulled from the container. - * - * @var \Drupal\Core\Cache\CacheContextInterface[] + * @var string[] */ - protected static $validCacheContexts; + protected static $validContextTokens; /** * Merges arrays of cache contexts and removes duplicates. @@ -69,22 +68,35 @@ public static function validateContexts(array $context_tokens) { // The set of existing (thus valid) cache contexts is stored on the // container; it's safe to statically cache this because it cannot change - // during the request. - if (!isset(static::$validCacheContexts)) { - static::$validCacheContexts = \Drupal::getContainer()->getParameter('cache_contexts'); + // during the request. Initialize the set of valid context tokens with this. + if (!isset(static::$validContextTokens)) { + static::$validContextTokens = \Drupal::getContainer()->getParameter('cache_contexts'); } - foreach ($context_tokens as $value) { - if (!is_string($value)) { - throw new \LogicException('Cache contexts must be strings, ' . gettype($value) . ' given.'); + $valid = array_flip(static::$validContextTokens); + foreach ($context_tokens as $context_token) { + if (!is_string($context_token)) { + throw new \LogicException('Cache contexts must be strings, ' . gettype($context_token) . ' given.'); + } + + if (isset($valid[$context_token])) { + continue; + } + + // If it's a valid context token, then the ID must be stored in the set + // of valid context tokens (since we initialized it with the list of cache + // context IDs using the container). In case of an invalid context token, + // throw an exception, otherwise cache it, including the parameter, to + // minimize the amount of work in future ::validateContexts() calls. + $context_id = $context_token; + if (strpos($context_id, ':') !== FALSE) { + $context_id = substr($context_id, 0, strpos($context_id, ':')); } - // If a cache context token has a parameter, drop it to get the cache - // context ID. - if (strpos($value, ':') !== FALSE) { - $value = substr($value, 0, strpos($value, ':')); + if (isset($valid[$context_id])) { + static::$validContextTokens[] = $context_token; } - if (!in_array($value, static::$validCacheContexts)) { - throw new \LogicException('"' . $value. '" is not a valid cache context ID.'); + else { + throw new \LogicException('"' . $context_id . '" is not a valid cache context ID.'); } } }