core/core.services.yml | 43 ++++++++++++++-------- core/lib/Drupal/Core/Cache/CacheContextsPass.php | 14 +++++++ .../Core/Cache/CalculatedCacheContextInterface.php | 9 +++-- core/lib/Drupal/Core/Cache/HostCacheContext.php | 33 +++++++++++++++++ .../Core/Cache/MenuActiveTrailCacheContext.php | 2 +- .../Drupal/Core/Cache/QueryArgsCacheContext.php | 40 ++++++++++++++++++++ .../Core/Cache/RequestStackCacheContextBase.php | 38 +++++++++++++++++++ core/lib/Drupal/Core/Cache/UrlCacheContext.php | 21 +---------- .../Drupal/Core/Menu/MenuActiveTrailInterface.php | 5 ++- core/modules/comment/comment.module | 2 +- .../system/src/Plugin/Block/SystemMenuBlock.php | 2 +- .../Tests/Cache/PageCacheTagsIntegrationTest.php | 8 ++-- 12 files changed, 168 insertions(+), 49 deletions(-) diff --git a/core/core.services.yml b/core/core.services.yml index 9b892ec..2eb4b93 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -6,24 +6,41 @@ parameters: factory.keyvalue.expirable: default: keyvalue.expirable.database services: - cache_factory: - class: Drupal\Core\Cache\CacheFactory - arguments: ['@settings', '%cache_default_bin_backends%'] - calls: - - [setContainer, ['@service_container']] - cache_contexts: - class: Drupal\Core\Cache\CacheContexts - arguments: ['@service_container', '%cache_contexts%' ] cache_context.url: class: Drupal\Core\Cache\UrlCacheContext arguments: ['@request_stack'] tags: - - { name: cache.context} - cache_context.pager: + - { name: cache.context } + cache_context.url.host: + class: Drupal\Core\Cache\HostCacheContext + arguments: ['@request_stack'] + tags: + - { name: cache.context } + cache_context.url.query_args: + class: Drupal\Core\Cache\QueryArgsCacheContext + arguments: ['@request_stack'] + tags: + - { name: cache.context } + cache_context.url.pager: class: Drupal\Core\Cache\PagerCacheContext arguments: ['@request_stack'] tags: - { name: cache.context} + cache_context.url.menu_active_trail: + class: Drupal\Core\Cache\MenuActiveTrailCacheContext + calls: + - [setContainer, ['@service_container']] + tags: + - { name: cache.context} + + cache_factory: + class: Drupal\Core\Cache\CacheFactory + arguments: ['@settings', '%cache_default_bin_backends%'] + calls: + - [setContainer, ['@service_container']] + cache_contexts: + class: Drupal\Core\Cache\CacheContexts + arguments: ['@service_container', '%cache_contexts%' ] cache_context.language: class: Drupal\Core\Cache\LanguageCacheContext arguments: ['@language_manager'] @@ -38,12 +55,6 @@ services: class: Drupal\Core\Cache\TimeZoneCacheContext tags: - { name: cache.context} - cache_context.menu.active_trail: - class: Drupal\Core\Cache\MenuActiveTrailCacheContext - calls: - - [setContainer, ['@service_container']] - tags: - - { name: cache.context} cache_tags.invalidator: parent: container.trait class: Drupal\Core\Cache\CacheTagsInvalidator diff --git a/core/lib/Drupal/Core/Cache/CacheContextsPass.php b/core/lib/Drupal/Core/Cache/CacheContextsPass.php index b1cb74e..576b2b5 100644 --- a/core/lib/Drupal/Core/Cache/CacheContextsPass.php +++ b/core/lib/Drupal/Core/Cache/CacheContextsPass.php @@ -28,6 +28,20 @@ public function process(ContainerBuilder $container) { } $cache_contexts[] = substr($id, 14); } + + // Validate. + sort($cache_contexts); + foreach ($cache_contexts as $id) { + // Validate the hierarchy of non-root-level cache contexts. + if (strpos($id, '.') !== FALSE) { + $parent = substr($id, 0, strrpos($id, '.')); + if (!in_array($parent, $cache_contexts)) { + throw new \InvalidArgumentException(sprintf('The service "%s" has an invalid service ID: the period indicates the hierarchy of cache contexts, therefore "%s" is considered the parent cache context, but no cache context service with that name was found.', $id, $parent)); + } + } + } + + $container->setParameter('cache_contexts', $cache_contexts); } diff --git a/core/lib/Drupal/Core/Cache/CalculatedCacheContextInterface.php b/core/lib/Drupal/Core/Cache/CalculatedCacheContextInterface.php index 795a512..38114c3 100644 --- a/core/lib/Drupal/Core/Cache/CalculatedCacheContextInterface.php +++ b/core/lib/Drupal/Core/Cache/CalculatedCacheContextInterface.php @@ -28,12 +28,13 @@ public static function getLabel(); * A cache context service's name is used as a token (placeholder) cache key, * and is then replaced with the string returned by this method. * - * @param string $parameter - * The parameter. + * @param string|null $parameter + * The parameter, or NULL to indicate all possible parameter values. * * @return string - * The string representation of the cache context. + * The string representation of the cache context. When $parameter is NULL, + * a value representing all possible parameters must be generated. */ - public function getContext($parameter); + public function getContext($parameter = NULL); } diff --git a/core/lib/Drupal/Core/Cache/HostCacheContext.php b/core/lib/Drupal/Core/Cache/HostCacheContext.php new file mode 100644 index 0000000..8a3af00 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/HostCacheContext.php @@ -0,0 +1,33 @@ +requestStack->getCurrentRequest()->getSchemeAndHttpHost(); + } + +} diff --git a/core/lib/Drupal/Core/Cache/MenuActiveTrailCacheContext.php b/core/lib/Drupal/Core/Cache/MenuActiveTrailCacheContext.php index 7c41bee..7f0e226 100644 --- a/core/lib/Drupal/Core/Cache/MenuActiveTrailCacheContext.php +++ b/core/lib/Drupal/Core/Cache/MenuActiveTrailCacheContext.php @@ -27,7 +27,7 @@ public static function getLabel() { /** * {@inheritdoc} */ - public function getContext($menu_name) { + public function getContext($menu_name = NULL) { $active_trail = $this->container->get('menu.active_trail') ->getActiveTrailIds($menu_name); return 'menu_trail.' . $menu_name . '|' . implode('|', $active_trail); diff --git a/core/lib/Drupal/Core/Cache/QueryArgsCacheContext.php b/core/lib/Drupal/Core/Cache/QueryArgsCacheContext.php new file mode 100644 index 0000000..7b5e01d --- /dev/null +++ b/core/lib/Drupal/Core/Cache/QueryArgsCacheContext.php @@ -0,0 +1,40 @@ +requestStack->getCurrentRequest()->getQueryString(); + } + else { + $query_args = []; + parse_str($this->requestStack->getCurrentRequest()->getQueryString(), $query_args); + return $query_args[$query_arg]; + } + } + +} diff --git a/core/lib/Drupal/Core/Cache/RequestStackCacheContextBase.php b/core/lib/Drupal/Core/Cache/RequestStackCacheContextBase.php new file mode 100644 index 0000000..b75f3d7 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/RequestStackCacheContextBase.php @@ -0,0 +1,38 @@ +requestStack = $request_stack; + } + +} diff --git a/core/lib/Drupal/Core/Cache/UrlCacheContext.php b/core/lib/Drupal/Core/Cache/UrlCacheContext.php index 308d182..1381093 100644 --- a/core/lib/Drupal/Core/Cache/UrlCacheContext.php +++ b/core/lib/Drupal/Core/Cache/UrlCacheContext.php @@ -7,29 +7,10 @@ namespace Drupal\Core\Cache; -use Symfony\Component\HttpFoundation\RequestStack; - /** * Defines the UrlCacheContext service, for "per page" caching. */ -class UrlCacheContext implements CacheContextInterface { - - /** - * The request stack. - * - * @var \Symfony\Component\HttpFoundation\RequestStack - */ - protected $requestStack; - - /** - * Constructs a new UrlCacheContext service. - * - * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack - * The request stack. - */ - public function __construct(RequestStack $request_stack) { - $this->requestStack = $request_stack; - } +class UrlCacheContext extends RequestStackCacheContextBase { /** * {@inheritdoc} diff --git a/core/lib/Drupal/Core/Menu/MenuActiveTrailInterface.php b/core/lib/Drupal/Core/Menu/MenuActiveTrailInterface.php index 49f4e99..be32e64 100644 --- a/core/lib/Drupal/Core/Menu/MenuActiveTrailInterface.php +++ b/core/lib/Drupal/Core/Menu/MenuActiveTrailInterface.php @@ -18,8 +18,9 @@ /** * Gets the active trail IDs of the specified menu tree. * - * @param string $menu_name - * The menu name of the requested tree. + * @param string|NULL $menu_name + * (optional) The menu name of the requested tree. If omitted, all menu + * trees will be searched. * * @return array * An array containing the active trail: a list of plugin IDs. diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 695018c..d4c2415 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -208,7 +208,7 @@ function comment_entity_build_defaults_alter(array &$build, EntityInterface $ent foreach ($entity->getFieldDefinitions() as $field_name => $definition) { if ($definition->getType() === 'comment' && ($display_options = $display->getComponent($field_name))) { $pager_id = $display_options['settings']['pager_id']; - $build['#cache']['contexts'][] = 'pager:' . $pager_id; + $build['#cache']['contexts'][] = 'url.pager:' . $pager_id; } } } diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php index c07fba2..0d9ab37 100644 --- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php @@ -201,7 +201,7 @@ protected function getRequiredCacheContexts() { $menu_name = $this->getDerivativeId(); return [ 'user.roles', - 'menu.active_trail:' . $menu_name, + 'url.menu_active_trail:' . $menu_name, ]; } diff --git a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php index b56a6ba..3fb4ea6 100644 --- a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php +++ b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php @@ -72,10 +72,10 @@ function testPageCacheTags() { $cache_contexts = [ 'language', - 'menu.active_trail:account', - 'menu.active_trail:footer', - 'menu.active_trail:main', - 'menu.active_trail:tools', + 'url.menu_active_trail:account', + 'url.menu_active_trail:footer', + 'url.menu_active_trail:main', + 'url.menu_active_trail:tools', 'theme', 'timezone', 'user.roles',