Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542

This commit is contained in:
Pantheon Automation 2015-08-27 12:03:05 -07:00 committed by Greg Anderson
parent 3b2511d96d
commit 81ccda77eb
2155 changed files with 54307 additions and 46870 deletions

View file

@ -24,19 +24,16 @@ class Cache {
/**
* Merges arrays of cache contexts and removes duplicates.
*
* @param string[]
* Arrays of cache contexts to merge.
* @param array $a
* Cache contexts array to merge.
* @param array $b
* Cache contexts array to merge.
*
* @return string[]
* The merged array of cache contexts.
*/
public static function mergeContexts() {
$cache_context_arrays = func_get_args();
$cache_contexts = [];
foreach ($cache_context_arrays as $contexts) {
$cache_contexts = array_merge($cache_contexts, $contexts);
}
$cache_contexts = array_unique($cache_contexts);
public static function mergeContexts(array $a = [], array $b = []) {
$cache_contexts = array_unique(array_merge($a, $b));
\Drupal::service('cache_contexts_manager')->validateTokens($cache_contexts);
sort($cache_contexts);
return $cache_contexts;
@ -53,19 +50,16 @@ class Cache {
* allows items to be invalidated based on all tags attached to the content
* they're constituted from.
*
* @param string[]
* Arrays of cache tags to merge.
* @param array $a
* Cache tags array to merge.
* @param array $b
* Cache tags array to merge.
*
* @return string[]
* The merged array of cache tags.
*/
public static function mergeTags() {
$cache_tag_arrays = func_get_args();
$cache_tags = [];
foreach ($cache_tag_arrays as $tags) {
$cache_tags = array_merge($cache_tags, $tags);
}
$cache_tags = array_unique($cache_tags);
public static function mergeTags(array $a = [], array $b = []) {
$cache_tags = array_unique(array_merge($a, $b));
static::validateTags($cache_tags);
sort($cache_tags);
return $cache_tags;
@ -76,29 +70,25 @@ class Cache {
*
* Ensures infinite max-age (Cache::PERMANENT) is taken into account.
*
* @param int
* Max-age values.
* @param int $a
* Max age value to merge.
* @param int $b
* Max age value to merge.
*
* @return int
* The minimum max-age value.
*/
public static function mergeMaxAges() {
$max_ages = func_get_args();
// Filter out all max-age values set to cache permanently.
if (in_array(Cache::PERMANENT, $max_ages)) {
$max_ages = array_filter($max_ages, function ($max_age) {
return $max_age !== Cache::PERMANENT;
});
// If nothing is left, then all max-age values were set to cache
// permanently, and then that is the result.
if (empty($max_ages)) {
return Cache::PERMANENT;
}
public static function mergeMaxAges($a = Cache::PERMANENT, $b = Cache::PERMANENT) {
// If one of the values is Cache::PERMANENT, return the other value.
if ($a === Cache::PERMANENT){
return $b;
}
if ($b === Cache::PERMANENT){
return $a;
}
return min($max_ages);
// If none or the values are Cache::PERMANENT, return the minimum value.
return min($a, $b);
}
/**

View file

@ -10,6 +10,9 @@ namespace Drupal\Core\Cache;
* Defines a generic class for passing cacheability metadata.
*
* @ingroup cache
*
* @todo Use RefinableCacheableDependencyInterface and the corresponding trait in
* https://www.drupal.org/node/2526326.
*/
class CacheableMetadata implements CacheableDependencyInterface {
@ -129,6 +132,35 @@ class CacheableMetadata implements CacheableDependencyInterface {
return $this;
}
/**
* Adds a dependency on an object: merges its cacheability metadata.
*
* @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $other_object
* The dependency. If the object implements CacheableDependencyInterface,
* then its cacheability metadata will be used. Otherwise, the passed in
* object must be assumed to be uncacheable, so max-age 0 is set.
*
* @return $this
*/
public function addCacheableDependency($other_object) {
if ($other_object instanceof CacheableDependencyInterface) {
$this->addCacheTags($other_object->getCacheTags());
$this->addCacheContexts($other_object->getCacheContexts());
if ($this->maxAge === Cache::PERMANENT) {
$this->maxAge = $other_object->getCacheMaxAge();
}
elseif (($max_age = $other_object->getCacheMaxAge()) && $max_age !== Cache::PERMANENT) {
$this->maxAge = Cache::mergeMaxAges($this->maxAge, $max_age);
}
}
else {
// Not a cacheable dependency, this can not be cached.
$this->maxAge = 0;
}
return $this;
}
/**
* Merges the values of another CacheableMetadata object with this one.
*
@ -139,7 +171,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
* A new CacheableMetadata object, with the merged data.
*/
public function merge(CacheableMetadata $other) {
$result = new static();
$result = clone $this;
// This is called many times per request, so avoid merging unless absolutely
// necessary.

View file

@ -7,18 +7,21 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\PermissionsHashGeneratorInterface;
/**
* Defines the AccountPermissionsCacheContext service, for "per permission" caching.
*
* Cache context ID: 'user.permissions'.
*/
class AccountPermissionsCacheContext extends UserCacheContext {
class AccountPermissionsCacheContext extends UserCacheContextBase implements CacheContextInterface {
/**
* The permissions hash generator.
*
* @var \Drupal\user\PermissionsHashInterface
* @var \Drupal\Core\Session\PermissionsHashGeneratorInterface
*/
protected $permissionsHashGenerator;
@ -27,7 +30,7 @@ class AccountPermissionsCacheContext extends UserCacheContext {
*
* @param \Drupal\Core\Session\AccountInterface $user
* The current user.
* @param \Drupal\user\PermissionsHashInterface $permissions_hash_generator
* @param \Drupal\Core\Session\PermissionsHashGeneratorInterface $permissions_hash_generator
* The permissions hash generator.
*/
public function __construct(AccountInterface $user, PermissionsHashGeneratorInterface $permissions_hash_generator) {
@ -46,7 +49,24 @@ class AccountPermissionsCacheContext extends UserCacheContext {
* {@inheritdoc}
*/
public function getContext() {
return 'ph.' . $this->permissionsHashGenerator->generate($this->user);
return $this->permissionsHashGenerator->generate($this->user);
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
$cacheable_metadata = new CacheableMetadata();
// The permissions hash changes when:
// - a user is updated to have different roles;
$tags = ['user:' . $this->user->id()];
// - a role is updated to have different permissions.
foreach ($this->user->getRoles() as $rid) {
$tags[] = "config:user.role.$rid";
}
return $cacheable_metadata->setCacheTags($tags);
}
}

View file

@ -31,4 +31,21 @@ interface CacheContextInterface {
*/
public function getContext();
/**
* Gets the cacheability metadata for the context.
*
* There are three valid cases for the returned CacheableMetadata object:
* - An empty object means this can be optimized away safely.
* - A max-age of 0 means that this context can never be optimized away. It
* will never bubble up and cache tags will not be used.
* - Any non-zero max-age and cache tags will bubble up into the cache item
* if this is optimized away to allow for invalidation if the context
* value changes.
*
*
* @return \Drupal\Core\Cache\CacheableMetadata
* A cacheable metadata object.
*/
public function getCacheableMetadata();
}

View file

@ -7,7 +7,7 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Cache\CacheableMetadata;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@ -99,23 +99,35 @@ class CacheContextsManager {
* @param string[] $context_tokens
* An array of cache context tokens.
*
* @return string[]
* The array of corresponding cache keys.
* @return \Drupal\Core\Cache\Context\ContextCacheKeys
* The ContextCacheKeys object containing the converted cache keys and
* cacheability metadata.
*
* @throws \InvalidArgumentException
* @throws \LogicException
* Thrown if any of the context tokens or parameters are not valid.
*/
public function convertTokensToKeys(array $context_tokens) {
$context_tokens = $this->optimizeTokens($context_tokens);
sort($context_tokens);
$keys = [];
foreach (static::parseTokens($context_tokens) as $context) {
list($context_id, $parameter) = $context;
if (!in_array($context_id, $this->contexts)) {
throw new \InvalidArgumentException(SafeMarkup::format('"@context" is not a valid cache context ID.', ['@context' => $context_id]));
}
$keys[] = $this->getService($context_id)->getContext($parameter);
$this->validateTokens($context_tokens);
$cacheable_metadata = new CacheableMetadata();
$optimized_tokens = $this->optimizeTokens($context_tokens);
// Iterate over cache contexts that have been optimized away and get their
// cacheability metadata.
foreach (static::parseTokens(array_diff($context_tokens, $optimized_tokens)) as $context_token) {
list($context_id, $parameter) = $context_token;
$context = $this->getService($context_id);
$cacheable_metadata = $cacheable_metadata->merge($context->getCacheableMetadata($parameter));
}
return $keys;
sort($optimized_tokens);
$keys = [];
foreach (array_combine($optimized_tokens, static::parseTokens($optimized_tokens)) as $context_token => $context) {
list($context_id, $parameter) = $context;
$keys[] = '[' . $context_token . ']=' . $this->getService($context_id)->getContext($parameter);
}
// Create the returned object and merge in the cacheability metadata.
$context_cache_keys = new ContextCacheKeys($keys);
return $context_cache_keys->merge($cacheable_metadata);
}
/**
@ -129,6 +141,9 @@ class CacheContextsManager {
* possible of a set of cache context tokens, that still captures the entire
* universe of variations.
*
* If a cache context is being optimized away, it is able to set cacheable
* metadata for itself which will be bubbled up.
*
* E.g. when caching per user ('user'), also caching per role ('user.roles')
* is meaningless because "per role" is implied by "per user".
*
@ -150,6 +165,14 @@ class CacheContextsManager {
public function optimizeTokens(array $context_tokens) {
$optimized_content_tokens = [];
foreach ($context_tokens as $context_token) {
// Extract the parameter if available.
$parameter = NULL;
$context_id = $context_token;
if (strpos($context_token, ':') !== FALSE) {
list($context_id, $parameter) = explode(':', $context_token);
}
// Context tokens without:
// - a period means they don't have a parent
// - a colon means they're not a specific value of a cache context
@ -157,6 +180,11 @@ class CacheContextsManager {
if (strpos($context_token, '.') === FALSE && strpos($context_token, ':') === FALSE) {
$optimized_content_tokens[] = $context_token;
}
// Check cacheability. If the context defines a max-age of 0, then it
// can not be optimized away. Pass the parameter along if we have one.
elseif ($this->getService($context_id)->getCacheableMetadata($parameter)->getCacheMaxAge() === 0) {
$optimized_content_tokens[] = $context_token;
}
// The context token has a period or a colon. Iterate over all ancestor
// cache contexts. If one exists, omit the context token.
else {

View file

@ -34,7 +34,32 @@ interface CalculatedCacheContextInterface {
* @return string
* The string representation of the cache context. When $parameter is NULL,
* a value representing all possible parameters must be generated.
*
* @throws \LogicException
* Thrown if the passed in parameter is invalid.
*/
public function getContext($parameter = NULL);
/**
* Gets the cacheability metadata for the context based on the parameter value.
*
* There are three valid cases for the returned CacheableMetadata object:
* - An empty object means this can be optimized away safely.
* - A max-age of 0 means that this context can never be optimized away. It
* will never bubble up and cache tags will not be used.
* - Any non-zero max-age and cache tags will bubble up into the cache item
* if this is optimized away to allow for invalidation if the context
* value changes.
*
* @param string|null $parameter
* The parameter, or NULL to indicate all possible parameter values.
*
* @return \Drupal\Core\Cache\CacheableMetadata
* A cacheable metadata object.
*
* @throws \LogicException
* Thrown if the passed in parameter is invalid.
*/
public function getCacheableMetadata($parameter = NULL);
}

View file

@ -0,0 +1,44 @@
<?php
/**
* @file
* Contains \Drupal\Core\Cache\Context\ContextCacheKeys.
*/
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* A value object to store generated cache keys with its cacheability metadata.
*/
class ContextCacheKeys extends CacheableMetadata {
/**
* The generated cache keys.
*
* @var string[]
*/
protected $keys;
/**
* Constructs a ContextCacheKeys object.
*
* @param string[] $keys
* The cache context keys.
*/
public function __construct(array $keys) {
$this->keys = $keys;
}
/**
* Gets the generated cache keys.
*
* @return string[]
* The cache keys.
*/
public function getKeys() {
return $this->keys;
}
}

View file

@ -7,8 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the CookiesCacheContext service, for "per cookie" caching.
*
* Cache context ID: 'cookies' (to vary by all cookies).
* Calculated cache context ID: 'cookies:%name', e.g. 'cookies:device_type' (to
* vary by the 'device_type' cookie).
*/
class CookiesCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
@ -31,4 +37,11 @@ class CookiesCacheContext extends RequestStackCacheContextBase implements Calcul
}
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($cookie = NULL) {
return new CacheableMetadata();
}
}

View file

@ -7,8 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the HeadersCacheContext service, for "per header" caching.
*
* Cache context ID: 'headers' (to vary by all headers).
* Calculated cache context ID: 'headers:%name', e.g. 'headers:X-Something' (to
* vary by the 'X-Something' header).
*/
class HeadersCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
@ -31,4 +37,11 @@ class HeadersCacheContext extends RequestStackCacheContextBase implements Calcul
}
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($header = NULL) {
return new CacheableMetadata();
}
}

View file

@ -7,10 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the IpCacheContext service, for "per IP address" caching.
*
* Cache context ID: 'ip'.
*/
class IpCacheContext extends RequestStackCacheContextBase {
class IpCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
/**
* {@inheritdoc}
@ -26,4 +30,11 @@ class IpCacheContext extends RequestStackCacheContextBase {
return $this->requestStack->getCurrentRequest()->getClientIp();
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -7,10 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the IsSuperUserCacheContext service, for "super user or not" caching.
*
* Cache context ID: 'user.is_super_user'.
*/
class IsSuperUserCacheContext extends UserCacheContext {
class IsSuperUserCacheContext extends UserCacheContextBase implements CacheContextInterface {
/**
* {@inheritdoc}
@ -26,4 +30,11 @@ class IsSuperUserCacheContext extends UserCacheContext {
return ((int) $this->user->id()) === 1 ? '1' : '0';
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Language\LanguageManagerInterface;
/**
@ -74,4 +75,11 @@ class LanguagesCacheContext implements CalculatedCacheContextInterface {
}
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($type = NULL) {
return new CacheableMetadata();
}
}

View file

@ -7,12 +7,13 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
use Symfony\Component\DependencyInjection\ContainerAware;
/**
* Defines the MenuActiveTrailsCacheContext service.
*
* This class is container-aware to avoid initializing the 'menu.active_trail'
* This class is container-aware to avoid initializing the 'menu.active_trails'
* service (and its dependencies) when it is not necessary.
*/
class MenuActiveTrailsCacheContext extends ContainerAware implements CalculatedCacheContextInterface {
@ -28,9 +29,24 @@ class MenuActiveTrailsCacheContext extends ContainerAware implements CalculatedC
* {@inheritdoc}
*/
public function getContext($menu_name = NULL) {
if (!$menu_name) {
throw new \LogicException('No menu name provided for menu.active_trails cache context.');
}
$active_trail = $this->container->get('menu.active_trail')
->getActiveTrailIds($menu_name);
return 'menu_trail.' . $menu_name . '|' . implode('|', $active_trail);
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($menu_name = NULL) {
if (!$menu_name) {
throw new \LogicException('No menu name provided for menu.active_trails cache context.');
}
$cacheable_metadata = new CacheableMetadata();
return $cacheable_metadata->setCacheTags(["config:system.menu.$menu_name"]);
}
}

View file

@ -7,8 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines a cache context for "per page in a pager" caching.
*
* Cache context ID: 'url.query_args.pagers' (to vary by all pagers).
* Calculated cache context ID: 'url.query_args.pagers:%pager_id', e.g.
* 'url.query_args.pagers:1' (to vary by the pager with ID 1).
*/
class PagersCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
@ -28,10 +34,17 @@ class PagersCacheContext extends RequestStackCacheContextBase implements Calcula
// The value of the 'page' query argument contains the information that
// controls *all* pagers.
if ($pager_id === NULL) {
return 'pager' . $this->requestStack->getCurrentRequest()->query->get('page', '');
return $this->requestStack->getCurrentRequest()->query->get('page', '');
}
return 'pager.' . $pager_id . '.' . pager_find_page($pager_id);
return $pager_id . '.' . pager_find_page($pager_id);
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($pager_id = NULL) {
return new CacheableMetadata();
}
}

View file

@ -7,12 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the QueryArgsCacheContext service, for "per query args" caching.
*
* A "host" is defined as the combination of URI scheme, domain name and port.
*
* @see Symfony\Component\HttpFoundation::getSchemeAndHttpHost()
* Cache context ID: 'url.query_args' (to vary by all query arguments).
* Calculated cache context ID: 'url.query_args:%key', e.g.'url.query_args:foo'
* (to vary by the 'foo' query argument).
*/
class QueryArgsCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
@ -35,4 +37,11 @@ class QueryArgsCacheContext extends RequestStackCacheContextBase implements Calc
}
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($query_arg = NULL) {
return new CacheableMetadata();
}
}

View file

@ -7,8 +7,12 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the RequestFormatCacheContext service, for "per format" caching.
*
* Cache context ID: 'request_format'.
*/
class RequestFormatCacheContext extends RequestStackCacheContextBase {
@ -26,4 +30,11 @@ class RequestFormatCacheContext extends RequestStackCacheContextBase {
return $this->requestStack->getCurrentRequest()->getRequestFormat();
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -11,8 +11,12 @@ use Symfony\Component\HttpFoundation\RequestStack;
/**
* Defines a base class for cache contexts depending only on the request stack.
*
* Subclasses need to implement either
* \Drupal\Core\Cache\Context\CacheContextInterface or
* \Drupal\Core\Cache\Context\CalculatedCacheContextInterface.
*/
abstract class RequestStackCacheContextBase implements CacheContextInterface {
abstract class RequestStackCacheContextBase {
/**
* The request stack.

View file

@ -7,10 +7,13 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Defines the RouteCacheContext service, for "per route" caching.
*
* Cache context ID: 'route'.
*/
class RouteCacheContext implements CacheContextInterface {
@ -45,4 +48,11 @@ class RouteCacheContext implements CacheContextInterface {
return $this->routeMatch->getRouteName() . hash('sha256', serialize($this->routeMatch->getRawParameters()->all()));
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -9,6 +9,8 @@ namespace Drupal\Core\Cache\Context;
/**
* Defines the RouteCacheContext service, for "per route name" caching.
*
* Cache context ID: 'route.name'.
*/
class RouteNameCacheContext extends RouteCacheContext {

View file

@ -0,0 +1,31 @@
<?php
/**
* @file
* Contains \Drupal\Core\Cache\Context\SessionCacheContext.
*/
namespace Drupal\Core\Cache\Context;
/**
* Defines the SessionCacheContext service, for "per session" caching.
*
* Cache context ID: 'session'.
*/
class SessionCacheContext extends RequestStackCacheContextBase {
/**
* {@inheritdoc}
*/
public static function getLabel() {
return t('Session');
}
/**
* {@inheritdoc}
*/
public function getContext() {
return $this->requestStack->getCurrentRequest()->getSession()->getId();
}
}

View file

@ -7,9 +7,13 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the SiteCacheContext service, for "per site" caching.
*
* Cache context ID: 'site'.
*
* A "site" is defined as the combination of URI scheme, domain name, port and
* base path. It allows for varying between the *same* site being accessed via
* different entry points. (Different sites in a multisite setup have separate
@ -18,7 +22,7 @@ namespace Drupal\Core\Cache\Context;
* @see \Symfony\Component\HttpFoundation\Request::getSchemeAndHttpHost()
* @see \Symfony\Component\HttpFoundation\Request::getBaseUrl()
*/
class SiteCacheContext extends RequestStackCacheContextBase {
class SiteCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
/**
* {@inheritdoc}
@ -35,4 +39,11 @@ class SiteCacheContext extends RequestStackCacheContextBase {
return $request->getSchemeAndHttpHost() . $request->getBaseUrl();
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -7,11 +7,13 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Theme\ThemeManagerInterface;
/**
* Defines the ThemeCacheContext service, for "per theme" caching.
*
* Cache context ID: 'theme'.
*/
class ThemeCacheContext implements CacheContextInterface {
@ -46,4 +48,11 @@ class ThemeCacheContext implements CacheContextInterface {
return $this->themeManager->getActiveTheme()->getName() ?: 'stark';
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -7,9 +7,13 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the TimeZoneCacheContext service, for "per time zone" caching.
*
* Cache context ID: 'timezone'.
*
* @see \Drupal\Core\Session\AccountProxy::setAccount()
*/
class TimeZoneCacheContext implements CacheContextInterface {
@ -30,4 +34,11 @@ class TimeZoneCacheContext implements CacheContextInterface {
return date_default_timezone_get();
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -7,10 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the UrlCacheContext service, for "per page" caching.
*
* Cache context ID: 'url'.
*/
class UrlCacheContext extends RequestStackCacheContextBase {
class UrlCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
/**
* {@inheritdoc}
@ -26,4 +30,11 @@ class UrlCacheContext extends RequestStackCacheContextBase {
return $this->requestStack->getCurrentRequest()->getUri();
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -7,22 +7,14 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the UserCacheContext service, for "per user" caching.
*
* Cache context ID: 'user'.
*/
class UserCacheContext implements CacheContextInterface {
/**
* Constructs a new UserCacheContext service.
*
* @param \Drupal\Core\Session\AccountInterface $user
* The current user.
*/
public function __construct(AccountInterface $user) {
$this->user = $user;
}
class UserCacheContext extends UserCacheContextBase implements CacheContextInterface {
/**
* {@inheritdoc}
@ -35,7 +27,14 @@ class UserCacheContext implements CacheContextInterface {
* {@inheritdoc}
*/
public function getContext() {
return "u." . $this->user->id();
return $this->user->id();
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -0,0 +1,38 @@
<?php
/**
* @file
* Contains \Drupal\Core\Cache\Context\UserCacheContextBase.
*/
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Session\AccountInterface;
/**
* Base class for user-based cache contexts.
*
* Subclasses need to implement either
* \Drupal\Core\Cache\Context\CacheContextInterface or
* \Drupal\Core\Cache\Context\CalculatedCacheContextInterface.
*/
abstract class UserCacheContextBase {
/**
* The account object.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $user;
/**
* Constructs a new UserCacheContextBase class.
*
* @param \Drupal\Core\Session\AccountInterface $user
* The current user.
*/
public function __construct(AccountInterface $user) {
$this->user = $user;
}
}

View file

@ -7,13 +7,19 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
/**
* Defines the UserRolesCacheContext service, for "per role" caching.
*
* Only use this cache context when checking explicitly for certain roles. Use
* user.permissions for anything that checks permissions.
*
* Cache context ID: 'user.roles' (to vary by all roles of the current user).
* Calculated cache context ID: 'user.roles:%role', e.g. 'user.roles:anonymous'
* (to vary by the presence/absence of a specific role).
*/
class UserRolesCacheContext extends UserCacheContext implements CalculatedCacheContextInterface{
class UserRolesCacheContext extends UserCacheContextBase implements CalculatedCacheContextInterface {
/**
* {@inheritdoc}
@ -34,11 +40,18 @@ class UserRolesCacheContext extends UserCacheContext implements CalculatedCacheC
return 'is-super-user';
}
if ($role === NULL) {
return 'r.' . implode(',', $this->user->getRoles());
return implode(',', $this->user->getRoles());
}
else {
return 'r.' . $role . '.' . (in_array($role, $this->user->getRoles()) ? '0' : '1');
return (in_array($role, $this->user->getRoles()) ? '0' : '1');
}
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($role = NULL) {
return (new CacheableMetadata())->setCacheTags(['user:' . $this->user->id()]);
}
}

View file

@ -0,0 +1,69 @@
<?php
/**
* @file
* Contains \Drupal\Core\Cache\RefinableCacheableDependencyInterface.
*/
namespace Drupal\Core\Cache;
/**
* Allows to add cacheability metadata to an object for the current runtime.
*
* This must be used when changing an object in a way that affects its
* cacheability. For example, when changing the active translation of an entity
* based on the current content language then a cache context for that must be
* added.
*/
interface RefinableCacheableDependencyInterface extends CacheableDependencyInterface {
/**
* Adds cache contexts.
*
* @param string[] $cache_contexts
* The cache contexts to be added.
*
* @return $this
*/
public function addCacheContexts(array $cache_contexts);
/**
* Adds cache tags.
*
* @param string[] $cache_tags
* The cache tags to be added.
*
* @return $this
*/
public function addCacheTags(array $cache_tags);
/**
* Merges the maximum age (in seconds) with the existing maximum age.
*
* The max age will be set to the given value if it is lower than the existing
* value.
*
* @param int $max_age
* The max age to associate.
*
* @return $this
*
* @throws \InvalidArgumentException
* Thrown if a non-integer value is supplied.
*/
public function mergeCacheMaxAge($max_age);
/**
* Adds a dependency on an object: merges its cacheability metadata.
*
* @param \Drupal\Core\Cache\CacheableDependencyInterface|object $other_object
* The dependency. If the object implements CacheableDependencyInterface,
* then its cacheability metadata will be used. Otherwise, the passed in
* object must be assumed to be uncacheable, so max-age 0 is set.
*
* @return $this
*
* @see \Drupal\Core\Cache\CacheableMetadata::createFromObject()
*/
public function addCacheableDependency($other_object);
}

View file

@ -0,0 +1,76 @@
<?php
/**
* @file
* Contains \Drupal\Core\Cache\RefinableCacheableDependencyTrait.
*/
namespace Drupal\Core\Cache;
/**
* Trait for \Drupal\Core\Cache\RefinableCacheableDependencyInterface.
*/
trait RefinableCacheableDependencyTrait {
/**
* Cache contexts.
*
* @var string[]
*/
protected $cacheContexts = [];
/**
* Cache tags.
*
* @var string[]
*/
protected $cacheTags = [];
/**
* Cache max-age.
*
* @var int
*/
protected $cacheMaxAge = Cache::PERMANENT;
/**
* {@inheritdoc}
*/
public function addCacheableDependency($other_object) {
if ($other_object instanceof CacheableDependencyInterface) {
$this->addCacheContexts($other_object->getCacheContexts());
$this->addCacheTags($other_object->getCacheTags());
$this->mergeCacheMaxAge($other_object->getCacheMaxAge());
}
else {
// Not a cacheable dependency, this can not be cached.
$this->maxAge = 0;
}
return $this;
}
/**
* {@inheritdoc}
*/
public function addCacheContexts(array $cache_contexts) {
$this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts);
return $this;
}
/**
* {@inheritdoc}
*/
public function addCacheTags(array $cache_tags) {
$this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags);
return $this;
}
/**
* {@inheritdoc}
*/
public function mergeCacheMaxAge($max_age) {
$this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age);
return $this;
}
}