diff --git a/core/lib/Drupal/Core/Access/AccessResult.php b/core/lib/Drupal/Core/Access/AccessResult.php index 76f02126460..d515933dab8 100644 --- a/core/lib/Drupal/Core/Access/AccessResult.php +++ b/core/lib/Drupal/Core/Access/AccessResult.php @@ -217,10 +217,15 @@ abstract class AccessResult implements AccessResultInterface, CacheableInterface /** * {@inheritdoc} - * - * AccessResult objects solely return cache context tokens, no static strings. */ public function getCacheKeys() { + return []; + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { sort($this->contexts); return $this->contexts; } @@ -329,22 +334,22 @@ abstract class AccessResult implements AccessResultInterface, CacheableInterface } /** - * Convenience method, adds the "cache_context.user.roles" cache context. + * Convenience method, adds the "user.roles" cache context. * * @return $this */ public function cachePerRole() { - $this->addCacheContexts(array('cache_context.user.roles')); + $this->addCacheContexts(array('user.roles')); return $this; } /** - * Convenience method, adds the "cache_context.user" cache context. + * Convenience method, adds the "user" cache context. * * @return $this */ public function cachePerUser() { - $this->addCacheContexts(array('cache_context.user')); + $this->addCacheContexts(array('user')); return $this; } @@ -459,7 +464,7 @@ abstract class AccessResult implements AccessResultInterface, CacheableInterface public function inheritCacheability(AccessResultInterface $other) { if ($other instanceof CacheableInterface) { $this->setCacheable($other->isCacheable()); - $this->addCacheContexts($other->getCacheKeys()); + $this->addCacheContexts($other->getCacheContexts()); $this->addCacheTags($other->getCacheTags()); // Use the lowest max-age. if ($this->getCacheMaxAge() === Cache::PERMANENT) { diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php index 83dd5deffd7..e0c6a12200f 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -205,8 +205,8 @@ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginIn $contexts = \Drupal::service("cache_contexts")->getLabels(); // Blocks are always rendered in the "per language" and "per theme" cache // contexts. No need to show those options to the end user. - unset($contexts['cache_context.language']); - unset($contexts['cache_context.theme']); + unset($contexts['language']); + unset($contexts['theme']); $form['cache']['contexts'] = array( '#type' => 'checkboxes', '#title' => t('Vary by context'), @@ -350,6 +350,13 @@ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginIn * {@inheritdoc} */ public function getCacheKeys() { + return []; + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { // Return the required cache contexts, merged with the user-configured cache // contexts, if any. return array_merge($this->getRequiredCacheContexts(), $this->configuration['cache']['contexts']); diff --git a/core/lib/Drupal/Core/Cache/CacheContexts.php b/core/lib/Drupal/Core/Cache/CacheContexts.php index 7f7badc1fb9..a2d8bdb6ea0 100644 --- a/core/lib/Drupal/Core/Cache/CacheContexts.php +++ b/core/lib/Drupal/Core/Cache/CacheContexts.php @@ -7,14 +7,15 @@ namespace Drupal\Core\Cache; +use Drupal\Component\Utility\String; use Drupal\Core\Database\Query\SelectInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Defines the CacheContexts service. * - * Converts string placeholders into their final string values, to be used as a - * cache key. + * Converts cache context IDs into their final string values, to be used as + * cache keys. */ class CacheContexts { @@ -26,9 +27,9 @@ class CacheContexts { protected $container; /** - * Available cache contexts and corresponding labels. + * Available cache context IDs and corresponding labels. * - * @var array + * @var string[] */ protected $contexts; @@ -37,10 +38,8 @@ class CacheContexts { * * @param \Symfony\Component\DependencyInjection\ContainerInterface $container * The current service container. - * @param array $contexts - * An array of key-value pairs, where the keys are service names (which also - * serve as the corresponding cache context token) and the values are the - * cache context labels. + * @param string[] $contexts + * An array of the available cache context IDs. */ public function __construct(ContainerInterface $container, array $contexts) { $this->container = $container; @@ -50,8 +49,8 @@ class CacheContexts { /** * Provides an array of available cache contexts. * - * @return array - * An array of available cache contexts. + * @return string[] + * An array of available cache context IDs. */ public function getAll() { return $this->contexts; @@ -76,33 +75,30 @@ class CacheContexts { /** * Converts cache context tokens to string representations of the context. * - * Cache keys may either be static (just strings) or tokens (placeholders - * that are converted to static keys by the @cache_contexts service, depending - * depending on the request). This is the default cache contexts service. + * @param string[] $contexts + * An array of cache context IDs. * - * @param array $keys - * An array of cache keys that may or may not contain cache context tokens. - * - * @return array + * @return string[] * A copy of the input, with cache context tokens converted. + * + * @throws \InvalidArgumentException */ - public function convertTokensToKeys(array $keys) { - $context_keys = array_intersect($keys, $this->getAll()); - $new_keys = $keys; - - // Iterate over the indices instead of the values so that the order of the - // cache keys are preserved. - foreach (array_keys($context_keys) as $index) { - $new_keys[$index] = $this->getContext($keys[$index]); + public function convertTokensToKeys(array $contexts) { + $materialized_contexts = []; + foreach ($contexts as $context) { + if (!in_array($context, $this->contexts)) { + throw new \InvalidArgumentException(String::format('"@context" is not a valid cache context ID.', ['@context' => $context])); + } + $materialized_contexts[] = $this->getContext($context); } - return $new_keys; + return $materialized_contexts; } /** * Provides the string representation of a cache context. * * @param string $context - * A cache context token of an available cache context service. + * A cache context ID of an available cache context service. * * @return string * The string representation of a cache context. @@ -112,16 +108,17 @@ class CacheContexts { } /** - * Retrieves a service from the container. + * Retrieves a cache context service from the container. * - * @param string $service - * The ID of the service to retrieve. + * @param string $context + * The context ID, which together with the service ID prefix allows the + * corresponding cache context service to be retrieved. * - * @return mixed - * The specified service. + * @return \Drupal\Core\Cache\CacheContextInterface + * The requested cache context service. */ - protected function getService($service) { - return $this->container->get($service); + protected function getService($context) { + return $this->container->get('cache_context.' . $context); } } diff --git a/core/lib/Drupal/Core/Cache/CacheContextsPass.php b/core/lib/Drupal/Core/Cache/CacheContextsPass.php index 645df0364d4..b1cb74e6886 100644 --- a/core/lib/Drupal/Core/Cache/CacheContextsPass.php +++ b/core/lib/Drupal/Core/Cache/CacheContextsPass.php @@ -21,7 +21,13 @@ class CacheContextsPass implements CompilerPassInterface { * Collects the cache contexts into the cache_contexts parameter. */ public function process(ContainerBuilder $container) { - $cache_contexts = array_keys($container->findTaggedServiceIds('cache.context')); + $cache_contexts = []; + foreach (array_keys($container->findTaggedServiceIds('cache.context')) as $id) { + if (strpos($id, 'cache_context.') !== 0) { + throw new \InvalidArgumentException(sprintf('The service "%s" has an invalid service ID: cache context service IDs must use the "cache_context." prefix. (The suffix is the cache context ID developers may use.)', $id)); + } + $cache_contexts[] = substr($id, 14); + } $container->setParameter('cache_contexts', $cache_contexts); } diff --git a/core/lib/Drupal/Core/Cache/CacheableInterface.php b/core/lib/Drupal/Core/Cache/CacheableInterface.php index 49388016edb..4af960ac650 100644 --- a/core/lib/Drupal/Core/Cache/CacheableInterface.php +++ b/core/lib/Drupal/Core/Cache/CacheableInterface.php @@ -9,6 +9,15 @@ namespace Drupal\Core\Cache; /** * Defines an interface for objects which are potentially cacheable. * + * All cacheability metadata exposed in this interface is bubbled to parent + * objects when they are cached: if a child object needs to be varied by certain + * cache contexts, invalidated by certain cache tags, expire after a certain + * maximum age, then so should any parent object. And if a child object is not + * cacheable, then neither is any parent object. + * The only cacheability metadata that must not be bubbled, are the cache keys: + * they're explicitly intended to be used to generate the cache item ID when + * caching the object they're on. + * * @ingroup cache */ interface CacheableInterface { @@ -16,21 +25,30 @@ interface CacheableInterface { /** * The cache keys associated with this potentially cacheable object. * - * Cache keys may either be static (just strings) or tokens (placeholders - * that are converted to static keys by the @cache_contexts service, depending - * depending on the request). - * - * @return array - * An array of strings or cache context tokens, used to generate a cache ID. - * - * @see \Drupal\Core\Cache\CacheContexts::convertTokensToKeys() + * @return string[] + * An array of strings, used to generate a cache ID. */ public function getCacheKeys(); + /** + * The cache contexts associated with this potentially cacheable object. + * + * Cache contexts are tokens: placeholders that are converted to cache keys by + * the @cache_contexts service. The replacement value depends on the request + * context (the current URL, language, and so on). They're converted before + * storing an object in cache. + * + * @return string[] + * An array of cache context tokens, used to generate a cache ID. + * + * @see \Drupal\Core\Cache\CacheContexts::convertTokensToKeys() + */ + public function getCacheContexts(); + /** * The cache tags associated with this potentially cacheable object. * - * @return array + * @return string[] * An array of cache tags. */ public function getCacheTags(); diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 420e78731f1..2f506c24304 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -181,11 +181,13 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf $this->entityTypeId, $entity->id(), $view_mode, - 'cache_context.theme', - 'cache_context.user.roles', + ), + 'contexts' => array( + 'theme', + 'user.roles', // @todo Move this out of here and into field formatters that depend // on the timezone. Blocked on https://drupal.org/node/2099137. - 'cache_context.timezone', + 'timezone', ), 'bin' => $this->cacheBin, ); diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index 69e99a0acf8..e0253b63ec7 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -537,7 +537,8 @@ class Renderer implements RendererInterface { * Creates the cache ID for a renderable element. * * This creates the cache ID string, either by returning the #cache['cid'] - * property if present or by building the cache ID out of the #cache['keys']. + * property if present or by building the cache ID out of the #cache['keys'] + + * #cache['contexts']. * * @param array $elements * A renderable array. @@ -550,11 +551,12 @@ class Renderer implements RendererInterface { return $elements['#cache']['cid']; } elseif (isset($elements['#cache']['keys'])) { - // Cache keys may either be static (just strings) or tokens (placeholders - // that are converted to static keys by the @cache_contexts service, - // depending on the request). - $keys = $this->cacheContexts->convertTokensToKeys($elements['#cache']['keys']); - return implode(':', $keys); + $cid_parts = $elements['#cache']['keys']; + if (isset($elements['#cache']['contexts'])) { + $contexts = $this->cacheContexts->convertTokensToKeys($elements['#cache']['contexts']); + $cid_parts = array_merge($cid_parts, $contexts); + } + return implode(':', $cid_parts); } return FALSE; } diff --git a/core/lib/Drupal/Core/Render/RendererInterface.php b/core/lib/Drupal/Core/Render/RendererInterface.php index f2bf6c40abc..06f49685e0c 100644 --- a/core/lib/Drupal/Core/Render/RendererInterface.php +++ b/core/lib/Drupal/Core/Render/RendererInterface.php @@ -96,9 +96,9 @@ interface RendererInterface { * associative array with one or several of the following keys: * - 'keys': An array of one or more keys that identify the element. If * 'keys' is set, the cache ID is created automatically from these keys. - * Cache keys may either be static (just strings) or tokens - * (placeholders that are converted to static keys by the - * 'cache_contexts' service, depending on the request). + * - 'contexts': An array of one or more cache context IDs. These are + * converted to a final value depending on the request. (e.g. 'user' is + * mapped to the current user's ID.) * - 'cid': Specify the cache ID directly. Either 'keys' or 'cid' is * required. If 'cid' is set, 'keys' is ignored. Use only if you have * special requirements. diff --git a/core/modules/block/src/BlockViewBuilder.php b/core/modules/block/src/BlockViewBuilder.php index 5dcbd9ff210..e56b24dc87a 100644 --- a/core/modules/block/src/BlockViewBuilder.php +++ b/core/modules/block/src/BlockViewBuilder.php @@ -78,20 +78,20 @@ class BlockViewBuilder extends EntityViewBuilder { if ($plugin->isCacheable()) { $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock'); - // Generic cache keys, with the block plugin's custom keys appended - // (usually cache context keys like 'cache_context.user.roles'). + // Generic cache keys, with the block plugin's custom keys appended. $default_cache_keys = array( 'entity_view', 'block', $entity->id(), - // Blocks are always rendered in a "per language" cache context. - 'cache_context.language', - // Blocks are always rendered in a "per theme" cache context. - 'cache_context.theme', + ); + $default_cache_contexts = array( + 'language', + 'theme', ); $max_age = $plugin->getCacheMaxAge(); $build[$entity_id]['#cache'] += array( 'keys' => array_merge($default_cache_keys, $plugin->getCacheKeys()), + 'contexts' => array_merge($default_cache_contexts, $plugin->getCacheContexts()), 'expire' => ($max_age === Cache::PERMANENT) ? Cache::PERMANENT : REQUEST_TIME + $max_age, ); } diff --git a/core/modules/block/src/Tests/BlockCacheTest.php b/core/modules/block/src/Tests/BlockCacheTest.php index 5ea01425eb4..615751da47d 100644 --- a/core/modules/block/src/Tests/BlockCacheTest.php +++ b/core/modules/block/src/Tests/BlockCacheTest.php @@ -72,12 +72,12 @@ class BlockCacheTest extends WebTestBase { } /** - * Test "cache_context.user.roles" cache context. + * Test "user.roles" cache context. */ function testCachePerRole() { $this->setBlockCacheConfig(array( 'max_age' => 600, - 'contexts' => array('cache_context.user.roles'), + 'contexts' => array('user.roles'), )); // Enable our test block. Set some content for it to display. @@ -167,12 +167,12 @@ class BlockCacheTest extends WebTestBase { } /** - * Test "cache_context.user" cache context. + * Test "user" cache context. */ function testCachePerUser() { $this->setBlockCacheConfig(array( 'max_age' => 600, - 'contexts' => array('cache_context.user'), + 'contexts' => array('user'), )); $current_content = $this->randomMachineName(); @@ -199,12 +199,12 @@ class BlockCacheTest extends WebTestBase { } /** - * Test "cache_context.url" cache context. + * Test "url" cache context. */ function testCachePerPage() { $this->setBlockCacheConfig(array( 'max_age' => 600, - 'contexts' => array('cache_context.url'), + 'contexts' => array('url'), )); $current_content = $this->randomMachineName(); diff --git a/core/modules/block/src/Tests/BlockInterfaceTest.php b/core/modules/block/src/Tests/BlockInterfaceTest.php index 11b676294f0..3c81acbf314 100644 --- a/core/modules/block/src/Tests/BlockInterfaceTest.php +++ b/core/modules/block/src/Tests/BlockInterfaceTest.php @@ -65,8 +65,8 @@ class BlockInterfaceTest extends KernelTestBase { $period[0] = '<' . t('no caching') . '>'; $period[\Drupal\Core\Cache\Cache::PERMANENT] = t('Forever'); $contexts = \Drupal::service("cache_contexts")->getLabels(); - unset($contexts['cache_context.theme']); - unset($contexts['cache_context.language']); + unset($contexts['theme']); + unset($contexts['language']); $expected_form = array( 'provider' => array( '#type' => 'value', diff --git a/core/modules/block/src/Tests/BlockViewBuilderTest.php b/core/modules/block/src/Tests/BlockViewBuilderTest.php index 972ded1df4a..506ce511bf7 100644 --- a/core/modules/block/src/Tests/BlockViewBuilderTest.php +++ b/core/modules/block/src/Tests/BlockViewBuilderTest.php @@ -214,7 +214,7 @@ class BlockViewBuilderTest extends KernelTestBase { $request_method = $request->server->get('REQUEST_METHOD'); $request->setMethod('GET'); - $default_keys = array('entity_view', 'block', 'test_block', 'cache_context.language', 'cache_context.theme'); + $default_keys = array('entity_view', 'block', 'test_block'); $default_tags = array('block_view', 'config:block.block.test_block', 'block_plugin:test_cache'); // Advanced: cached block, but an alter hook adds an additional cache key. @@ -223,7 +223,7 @@ class BlockViewBuilderTest extends KernelTestBase { )); $alter_add_key = $this->randomMachineName(); \Drupal::state()->set('block_test_view_alter_cache_key', $alter_add_key); - $cid = 'entity_view:block:test_block:en:core:' . $alter_add_key; + $cid = 'entity_view:block:test_block:' . $alter_add_key . ':en:core'; $expected_keys = array_merge($default_keys, array($alter_add_key)); $build = $this->getBlockRenderArray(); $this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.'); @@ -290,11 +290,12 @@ class BlockViewBuilderTest extends KernelTestBase { // Second: the "per URL" cache context. $this->setBlockCacheConfig(array( 'max_age' => 600, - 'contexts' => array('cache_context.url'), + 'contexts' => array('url'), )); $old_cid = $cid; $build = $this->getBlockRenderArray(); - $cid = implode(':', $cache_contexts->convertTokensToKeys($build['#cache']['keys'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid = implode(':', $cid_parts); drupal_render($build); $this->assertTrue($this->container->get('cache.render', $cid), 'The block render element has been cached.'); $this->assertNotEqual($cid, $old_cid, 'The cache ID has changed.'); @@ -307,7 +308,8 @@ class BlockViewBuilderTest extends KernelTestBase { $this->container->set('cache_context.url', $temp_context); $old_cid = $cid; $build = $this->getBlockRenderArray(); - $cid = implode(':', $cache_contexts->convertTokensToKeys($build['#cache']['keys'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid = implode(':', $cid_parts); drupal_render($build); $this->assertTrue($this->container->get('cache.render', $cid), 'The block render element has been cached.'); $this->assertNotEqual($cid, $old_cid, 'The cache ID has changed.'); diff --git a/core/modules/book/src/Plugin/Block/BookNavigationBlock.php b/core/modules/book/src/Plugin/Block/BookNavigationBlock.php index 4369756d022..4a080af3a98 100644 --- a/core/modules/book/src/Plugin/Block/BookNavigationBlock.php +++ b/core/modules/book/src/Plugin/Block/BookNavigationBlock.php @@ -201,7 +201,7 @@ class BookNavigationBlock extends BlockBase implements ContainerFactoryPluginInt protected function getRequiredCacheContexts() { // The "Book navigation" block must be cached per role: different roles may // have access to different menu links. - return array('cache_context.user.roles'); + return array('user.roles'); } } diff --git a/core/modules/help/src/Plugin/Block/HelpBlock.php b/core/modules/help/src/Plugin/Block/HelpBlock.php index 7e490f5c773..7038c9dc855 100644 --- a/core/modules/help/src/Plugin/Block/HelpBlock.php +++ b/core/modules/help/src/Plugin/Block/HelpBlock.php @@ -141,7 +141,7 @@ class HelpBlock extends BlockBase implements ContainerFactoryPluginInterface { protected function getRequiredCacheContexts() { // The "Help" block must be cached per URL: help is defined for a // given path, and does not come with any access restrictions. - return array('cache_context.url'); + return array('url'); } } diff --git a/core/modules/node/src/NodeGrantDatabaseStorage.php b/core/modules/node/src/NodeGrantDatabaseStorage.php index d9e8d5cc5fc..da6522dc0ef 100644 --- a/core/modules/node/src/NodeGrantDatabaseStorage.php +++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -107,7 +107,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface { // know it for a fact. $set_cacheability = function (AccessResult $access_result) use ($operation) { if ($operation === 'view') { - return $access_result->addCacheContexts(['cache_context.node_view_grants']); + return $access_result->addCacheContexts(['node_view_grants']); } else { return $access_result->setCacheable(FALSE); diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php index 0bfade440a3..8ddcc46508e 100644 --- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php @@ -208,7 +208,7 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa protected function getRequiredCacheContexts() { // Menu blocks must be cached per role: different roles may have access to // different menu links. - return array('cache_context.user.roles'); + return array('user.roles'); } } diff --git a/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php b/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php index 955d75b544c..b0a63432d4b 100644 --- a/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php +++ b/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php @@ -57,7 +57,8 @@ class EntityViewBuilderTest extends EntityUnitTestBase { // Get a fully built entity view render array. $entity_test->save(); $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full'); - $cid = implode(':', $cache_contexts->convertTokensToKeys($build['#cache']['keys'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid = implode(':', $cid_parts); $bin = $build['#cache']['bin']; // Mock the build array to not require the theme registry. @@ -106,7 +107,8 @@ class EntityViewBuilderTest extends EntityUnitTestBase { // Get a fully built entity view render array for the referenced entity. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test_reference, 'full'); - $cid_reference = implode(':', $cache_contexts->convertTokensToKeys($build['#cache']['keys'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid_reference = implode(':', $cid_parts); $bin_reference = $build['#cache']['bin']; // Mock the build array to not require the theme registry. @@ -124,7 +126,8 @@ class EntityViewBuilderTest extends EntityUnitTestBase { // Get a fully built entity view render array. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full'); - $cid = implode(':', $cache_contexts->convertTokensToKeys($build['#cache']['keys'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid = implode(':', $cid_parts); $bin = $build['#cache']['bin']; // Mock the build array to not require the theme registry. @@ -154,7 +157,7 @@ class EntityViewBuilderTest extends EntityUnitTestBase { // Test a view mode in default conditions: render caching is enabled for // the entity type and the view mode. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full'); - $this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags', 'keys', 'bin') , 'A view mode with render cache enabled has the correct output (cache tags, keys and bin).'); + $this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags', 'keys', 'contexts', 'bin') , 'A view mode with render cache enabled has the correct output (cache tags, keys, contexts and bin).'); // Test that a view mode can opt out of render caching. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'test'); diff --git a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php index da5651c6ee5..42d2d2a4100 100644 --- a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php +++ b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php @@ -23,6 +23,7 @@ class AccessResultTest extends UnitTestCase { protected function assertDefaultCacheability(AccessResult $access) { $this->assertTrue($access->isCacheable()); $this->assertSame([], $access->getCacheKeys()); + $this->assertSame([], $access->getCacheContexts()); $this->assertSame([], $access->getCacheTags()); $this->assertSame('default', $access->getCacheBin()); $this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge()); @@ -318,7 +319,7 @@ class AccessResultTest extends UnitTestCase { /** * @covers ::addCacheContexts * @covers ::resetCacheContexts - * @covers ::getCacheKeys + * @covers ::getCacheContexts * @covers ::cachePerRole * @covers ::cachePerUser * @covers ::allowedIfHasPermission @@ -331,31 +332,31 @@ class AccessResultTest extends UnitTestCase { $this->assertTrue($access->isCacheable()); $this->assertSame('default', $access->getCacheBin()); $this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge()); - $this->assertSame($contexts, $access->getCacheKeys()); + $this->assertSame($contexts, $access->getCacheContexts()); $this->assertSame([], $access->getCacheTags()); }; - $access = AccessResult::neutral()->addCacheContexts(['cache_context.foo']); - $verify($access, ['cache_context.foo']); + $access = AccessResult::neutral()->addCacheContexts(['foo']); + $verify($access, ['foo']); // Verify resetting works. $access->resetCacheContexts(); $verify($access, []); // Verify idempotency. - $access->addCacheContexts(['cache_context.foo']) - ->addCacheContexts(['cache_context.foo']); - $verify($access, ['cache_context.foo']); + $access->addCacheContexts(['foo']) + ->addCacheContexts(['foo']); + $verify($access, ['foo']); // Verify same values in different call order yields the same result. $access->resetCacheContexts() - ->addCacheContexts(['cache_context.foo']) - ->addCacheContexts(['cache_context.bar']); - $verify($access, ['cache_context.bar', 'cache_context.foo']); + ->addCacheContexts(['foo']) + ->addCacheContexts(['bar']); + $verify($access, ['bar', 'foo']); $access->resetCacheContexts() - ->addCacheContexts(['cache_context.bar']) - ->addCacheContexts(['cache_context.foo']); - $verify($access, ['cache_context.bar', 'cache_context.foo']); + ->addCacheContexts(['bar']) + ->addCacheContexts(['foo']); + $verify($access, ['bar', 'foo']); // ::cachePerRole() convenience method. - $contexts = array('cache_context.user.roles'); + $contexts = array('user.roles'); $a = AccessResult::neutral()->addCacheContexts($contexts); $verify($a, $contexts); $b = AccessResult::neutral()->cachePerRole(); @@ -363,7 +364,7 @@ class AccessResultTest extends UnitTestCase { $this->assertEquals($a, $b); // ::cachePerUser() convenience method. - $contexts = array('cache_context.user'); + $contexts = array('user'); $a = AccessResult::neutral()->addCacheContexts($contexts); $verify($a, $contexts); $b = AccessResult::neutral()->cachePerUser(); @@ -371,7 +372,7 @@ class AccessResultTest extends UnitTestCase { $this->assertEquals($a, $b); // Both. - $contexts = array('cache_context.user', 'cache_context.user.roles'); + $contexts = array('user', 'user.roles'); $a = AccessResult::neutral()->addCacheContexts($contexts); $verify($a, $contexts); $b = AccessResult::neutral()->cachePerRole()->cachePerUser(); @@ -387,7 +388,7 @@ class AccessResultTest extends UnitTestCase { ->method('hasPermission') ->with('may herd llamas') ->will($this->returnValue(FALSE)); - $contexts = array('cache_context.user.roles'); + $contexts = array('user.roles'); // Verify the object when using the ::allowedIfHasPermission() convenience // static method. @@ -410,7 +411,7 @@ class AccessResultTest extends UnitTestCase { $this->assertTrue($access->isCacheable()); $this->assertSame('default', $access->getCacheBin()); $this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge()); - $this->assertSame([], $access->getCacheKeys()); + $this->assertSame([], $access->getCacheContexts()); $this->assertSame($tags, $access->getCacheTags()); }; @@ -471,7 +472,7 @@ class AccessResultTest extends UnitTestCase { $other = AccessResult::allowed()->setCacheMaxAge(1500)->cachePerRole()->addCacheTags(['node:20011988']); $this->assertTrue($access->inheritCacheability($other) instanceof AccessResult); $this->assertTrue($access->isCacheable()); - $this->assertSame(['cache_context.user.roles'], $access->getCacheKeys()); + $this->assertSame(['user.roles'], $access->getCacheContexts()); $this->assertSame(['node:20011988'], $access->getCacheTags()); $this->assertSame('default', $access->getCacheBin()); $this->assertSame(1500, $access->getCacheMaxAge()); @@ -481,7 +482,7 @@ class AccessResultTest extends UnitTestCase { $other = AccessResult::forbidden()->addCacheTags(['node:14031991'])->setCacheMaxAge(86400); $this->assertTrue($access->inheritCacheability($other) instanceof AccessResult); $this->assertTrue($access->isCacheable()); - $this->assertSame(['cache_context.user'], $access->getCacheKeys()); + $this->assertSame(['user'], $access->getCacheContexts()); $this->assertSame(['node:14031991'], $access->getCacheTags()); $this->assertSame('default', $access->getCacheBin()); $this->assertSame(43200, $access->getCacheMaxAge()); diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php index ca868e39790..fff9df226ad 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php @@ -27,17 +27,32 @@ class CacheContextsTest extends UnitTestCase { $cache_contexts = new CacheContexts($container, $this->getContextsFixture()); $new_keys = $cache_contexts->convertTokensToKeys( - array("non-cache-context", "cache_context.foo") + ['foo'] ); - $expected = array("non-cache-context", "bar"); + $expected = ['bar']; $this->assertEquals($expected, $new_keys); } + /** + * @covers ::convertTokensToKeys + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage "non-cache-context" is not a valid cache context ID. + */ + public function testInvalidContext() { + $container = $this->getMockContainer(); + $cache_contexts = new CacheContexts($container, $this->getContextsFixture()); + + $cache_contexts->convertTokensToKeys( + ["non-cache-context"] + ); + } + public function testAvailableContextStrings() { $cache_contexts = new CacheContexts($this->getMockContainer(), $this->getContextsFixture()); $contexts = $cache_contexts->getAll(); - $this->assertEquals(array("cache_context.foo"), $contexts); + $this->assertEquals(array("foo"), $contexts); } public function testAvailableContextLabels() { @@ -49,12 +64,12 @@ class CacheContextsTest extends UnitTestCase { $cache_contexts = new CacheContexts($container, $this->getContextsFixture()); $labels = $cache_contexts->getLabels(); - $expected = array("cache_context.foo" => "Foo"); + $expected = array("foo" => "Foo"); $this->assertEquals($expected, $labels); } protected function getContextsFixture() { - return array('cache_context.foo'); + return array('foo'); } protected function getMockContainer() {