Issue #2329101 by Wim Leers: CacheableInterface only has a getCacheKeys() method, no getCacheContexts(), leads to awkward implementations
parent
9d4d62d033
commit
460af4c9f3
|
@ -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) {
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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.');
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue