diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php index bc93ea3..f282a77 100644 --- a/core/lib/Drupal/Core/Cache/Cache.php +++ b/core/lib/Drupal/Core/Cache/Cache.php @@ -22,13 +22,6 @@ class Cache { const PERMANENT = CacheBackendInterface::CACHE_PERMANENT; /** - * The set of valid cache context tokens. - * - * @var string[] - */ - protected static $validContextTokens; - - /** * Merges arrays of cache contexts and removes duplicates. * * @param string[] … @@ -44,69 +37,12 @@ public static function mergeContexts() { $cache_contexts = array_merge($cache_contexts, $contexts); } $cache_contexts = array_unique($cache_contexts); - static::validateContexts($cache_contexts); + \Drupal::service('cache_contexts')->validate($cache_contexts); sort($cache_contexts); return $cache_contexts; } /** - * Validates an array of cache contexts. - * - * Can be called before using cache tags in operations, to ensure validity. - * - * @param string[] $context_tokens - * An array of cache context tokens. - * - * @throws \LogicException - * - * @see \Drupal\Core\Cache\CacheContexts::parseTokens() - */ - public static function validateContexts(array $context_tokens) { - if (empty($context_tokens)) { - return; - } - - // Initialize the set of valid context tokens with the container's contexts. - if (!isset(static::$validContextTokens)) { - static::$validContextTokens = array_flip(\Drupal::getContainer()->getParameter('cache_contexts')); - } - - 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(static::$validContextTokens[$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; - $colon_pos = strpos($context_id, ':'); - if ($colon_pos !== FALSE) { - $context_id = substr($context_id, 0, $colon_pos); - } - if (isset(static::$validContextTokens[$context_id])) { - static::$validContextTokens[$context_token] = TRUE; - } - else { - throw new \LogicException('"' . $context_id . '" is not a valid cache context ID.'); - } - } - } - - /** - * Refreshes any static caches. - */ - public static function refresh() { - static::$validContextTokens = NULL; - } - - /** * Merges arrays of cache tags and removes duplicates. * * The cache tags array is returned in a format that is valid for diff --git a/core/lib/Drupal/Core/Cache/CacheContexts.php b/core/lib/Drupal/Core/Cache/CacheContexts.php index 33f86b1..4981539 100644 --- a/core/lib/Drupal/Core/Cache/CacheContexts.php +++ b/core/lib/Drupal/Core/Cache/CacheContexts.php @@ -54,6 +54,44 @@ public function __construct(ContainerInterface $container, array $contexts) { $this->contexts = $contexts; } + public function validate(array $context_tokens = []) { + if (empty($context_tokens)) { + return; + } + + // Initialize the set of valid context tokens with the container's contexts. + if (!isset($this->validContextTokens)) { + $this->validContextTokens = array_flip($this->contexts); + } + + 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($this->validContextTokens[$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; + $colon_pos = strpos($context_id, ':'); + if ($colon_pos !== FALSE) { + $context_id = substr($context_id, 0, $colon_pos); + } + if (isset($this->validContextTokens[$context_id])) { + $this->validContextTokens[$context_token] = TRUE; + } + else { + throw new \LogicException('"' . $context_id . '" is not a valid cache context ID.'); + } + } + } + /** * Provides an array of available cache contexts. * diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index 3567d57..172bfc0 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -274,10 +274,6 @@ public function install(array $module_list, $enable_dependencies = TRUE) { // Allow the module to perform install tasks. $this->moduleHandler->invoke($module, 'install'); - // Refresh any static caches in the Cache class (e.g. to ensure it has - // the correct set of cache contexts). - Cache::refresh(); - // Record the fact that it was installed. \Drupal::logger('system')->info('%module module installed.', array('%module' => $module)); } diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php index 8b806a6..14b839b 100644 --- a/core/modules/simpletest/src/KernelTestBase.php +++ b/core/modules/simpletest/src/KernelTestBase.php @@ -9,7 +9,6 @@ use Drupal\Component\Utility\String; use Drupal\Component\Utility\Variable; -use Drupal\Core\Cache\Cache; use Drupal\Core\Database\Database; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DrupalKernel; @@ -489,9 +488,6 @@ protected function enableModules(array $modules) { } $active_storage->write('core.extension', $extensions); - // Clear some static caches. - Cache::refresh(); - // Update the kernel to make their services available. $module_filenames = $module_handler->getModuleList(); $this->kernel->updateModules($module_filenames, $module_filenames); diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php index 1563a6d..4fec080 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php @@ -10,6 +10,7 @@ use Drupal\Core\Cache\CacheContexts; use Drupal\Core\Cache\CacheContextInterface; use Drupal\Core\Cache\CalculatedCacheContextInterface; +use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Tests\UnitTestCase; use Symfony\Component\DependencyInjection\Container; @@ -108,6 +109,53 @@ protected function getMockContainer() { return $container; } + /** + * Provides a list of cache context token arrays. + * + * @return array + */ + public function validateContextsProvider() { + return [ + [[], FALSE], + [['foo'], FALSE], + [['foo', 'foo.bar'], FALSE], + [['foo', 'baz:llama'], FALSE], + // Invalid. + [[FALSE], 'Cache contexts must be strings, boolean given.'], + [[TRUE], 'Cache contexts must be strings, boolean given.'], + [['foo', FALSE], 'Cache contexts must be strings, boolean given.'], + [[NULL], 'Cache contexts must be strings, NULL given.'], + [['foo', NULL], 'Cache contexts must be strings, NULL given.'], + [[1337], 'Cache contexts must be strings, integer given.'], + [['foo', 1337], 'Cache contexts must be strings, integer given.'], + [[3.14], 'Cache contexts must be strings, double given.'], + [['foo', 3.14], 'Cache contexts must be strings, double given.'], + [[[]], 'Cache contexts must be strings, array given.'], + [['foo', []], 'Cache contexts must be strings, array given.'], + [['foo', ['bar']], 'Cache contexts must be strings, array given.'], + [[new \stdClass()], 'Cache contexts must be strings, object given.'], + [['foo', new \stdClass()], 'Cache contexts must be strings, object given.'], + // Non-existing. + [['foo.bar', 'qux'], '"qux" is not a valid cache context ID.'], + [['qux', 'baz'], '"qux" is not a valid cache context ID.'], + ]; + } + + /** + * @covers ::validate + * + * @dataProvider validateContextsProvider + */ + public function testValidateContexts(array $contexts, $expected_exception_message) { + $container = new ContainerBuilder(); + $cache_contexts = new CacheContexts($container, ['foo', 'foo.bar', 'baz']); + if ($expected_exception_message !== FALSE) { + $this->setExpectedException('LogicException', $expected_exception_message); + } + // If it doesn't throw an exception, validate() returns NULL. + $this->assertNull($cache_contexts->validate($contexts)); + } + } /** diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php index b601a7d..c2e61a1 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php @@ -153,56 +153,4 @@ public function testBuildTags($prefix, array $suffixes, array $expected, $glue = $this->assertEquals($expected, Cache::buildTags($prefix, $suffixes, $glue)); } - /** - * Provides a list of cache context token arrays. - * - * @return array - */ - public function validateContextsProvider() { - return [ - [[], FALSE], - [['foo'], FALSE], - [['foo', 'foo.bar'], FALSE], - [['foo', 'baz:llama'], FALSE], - // Invalid. - [[FALSE], 'Cache contexts must be strings, boolean given.'], - [[TRUE], 'Cache contexts must be strings, boolean given.'], - [['foo', FALSE], 'Cache contexts must be strings, boolean given.'], - [[NULL], 'Cache contexts must be strings, NULL given.'], - [['foo', NULL], 'Cache contexts must be strings, NULL given.'], - [[1337], 'Cache contexts must be strings, integer given.'], - [['foo', 1337], 'Cache contexts must be strings, integer given.'], - [[3.14], 'Cache contexts must be strings, double given.'], - [['foo', 3.14], 'Cache contexts must be strings, double given.'], - [[[]], 'Cache contexts must be strings, array given.'], - [['foo', []], 'Cache contexts must be strings, array given.'], - [['foo', ['bar']], 'Cache contexts must be strings, array given.'], - [[new \stdClass()], 'Cache contexts must be strings, object given.'], - [['foo', new \stdClass()], 'Cache contexts must be strings, object given.'], - // Non-existing. - [['foo.bar', 'qux'], '"qux" is not a valid cache context ID.'], - [['qux', 'baz'], '"qux" is not a valid cache context ID.'], - ]; - } - - /** - * @covers ::validateContexts - * - * @dataProvider validateContextsProvider - */ - public function testValidateContexts(array $contexts, $expected_exception_message) { - $container = new ContainerBuilder(); - $container->setParameter('cache_contexts', [ - 'foo', - 'foo.bar', - 'baz', - ]); - \Drupal::setContainer($container); - if ($expected_exception_message !== FALSE) { - $this->setExpectedException('LogicException', $expected_exception_message); - } - // If it doesn't throw an exception, validateContexts() returns NULL. - $this->assertNull(Cache::validateContexts($contexts)); - } - } diff --git a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php index c43712a..e2cfd91 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php @@ -24,11 +24,6 @@ class RendererBubblingTest extends RendererTestBase { protected function setUp() { parent::setUp(); - // Ensure the container lists the valid cache contexts. - $container = \Drupal::getContainer(); - $container->setParameter('cache_contexts', ['foo', 'bar', 'baz', 'user.roles', 'child.cache_context']); - \Drupal::setContainer($container); - $this->setUpRequest(); $this->setupMemoryCache(); }