Issue #2329101 by Wim Leers: CacheableInterface only has a getCacheKeys() method, no getCacheContexts(), leads to awkward implementations

8.0.x
catch 2015-02-20 09:18:26 +00:00
parent 9d4d62d033
commit 460af4c9f3
19 changed files with 175 additions and 117 deletions

View File

@ -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) {

View File

@ -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']);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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,
);

View File

@ -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;
}

View File

@ -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.

View File

@ -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,
);
}

View File

@ -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();

View File

@ -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',

View File

@ -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.');

View File

@ -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');
}
}

View File

@ -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');
}
}

View File

@ -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);

View File

@ -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');
}
}

View File

@ -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');

View File

@ -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());

View File

@ -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() {