diff --git a/core/lib/Drupal/Core/Access/AccessResult.php b/core/lib/Drupal/Core/Access/AccessResult.php
index 9c4e42f..269c83b 100644
--- a/core/lib/Drupal/Core/Access/AccessResult.php
+++ b/core/lib/Drupal/Core/Access/AccessResult.php
@@ -25,6 +25,9 @@
*
* When using ::orIf() and ::andIf(), cacheability metadata will be merged
* accordingly as well.
+ *
+ * @todo Use MutableCacheableDependencyInterface and the corresponding trait in
+ * https://www.drupal.org/node/2526326.
*/
abstract class AccessResult implements AccessResultInterface, CacheableDependencyInterface {
diff --git a/core/lib/Drupal/Core/Cache/CacheableMetadata.php b/core/lib/Drupal/Core/Cache/CacheableMetadata.php
index a0c1ba8..e0bb6ac 100644
--- a/core/lib/Drupal/Core/Cache/CacheableMetadata.php
+++ b/core/lib/Drupal/Core/Cache/CacheableMetadata.php
@@ -10,6 +10,9 @@
* Defines a generic class for passing cacheability metadata.
*
* @ingroup cache
+ *
+ * @todo Use MutableCacheableDependencyInterface and the corresponding trait in
+ * https://www.drupal.org/node/2526326.
*/
class CacheableMetadata implements CacheableDependencyInterface {
diff --git a/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php
new file mode 100644
index 0000000..978a604
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php
@@ -0,0 +1,54 @@
+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 setCacheMaxAgeIfLower($max_age) {
+ $this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age);
+ return $this;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigBase.php b/core/lib/Drupal/Core/Config/ConfigBase.php
index eee76a2..51801b1 100644
--- a/core/lib/Drupal/Core/Config/ConfigBase.php
+++ b/core/lib/Drupal/Core/Config/ConfigBase.php
@@ -11,6 +11,8 @@
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
+use Drupal\Core\Cache\MutableCacheableDependencyInterface;
+use Drupal\Core\Cache\MutableCacheableDependencyTrait;
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
/**
@@ -28,8 +30,9 @@
* @see \Drupal\Core\Config\Config
* @see \Drupal\Core\Theme\ThemeSettings
*/
-abstract class ConfigBase implements CacheableDependencyInterface {
+abstract class ConfigBase implements CacheableDependencyInterface, MutableCacheableDependencyInterface {
use DependencySerializationTrait;
+ use MutableCacheableDependencyTrait;
/**
* The name of the configuration object.
@@ -269,21 +272,21 @@ public function merge(array $data_to_merge) {
* {@inheritdoc}
*/
public function getCacheContexts() {
- return [];
+ return $this->cacheContexts;
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
- return ['config:' . $this->name];
+ return Cache::mergeTags(['config:' . $this->name], $this->cacheTags);
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
- return Cache::PERMANENT;
+ return $this->cacheMaxAge;
}
}
diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php
index cdfd951..907ea6d 100644
--- a/core/lib/Drupal/Core/Config/ConfigFactory.php
+++ b/core/lib/Drupal/Core/Config/ConfigFactory.php
@@ -126,6 +126,10 @@ protected function doGet($name, $immutable = TRUE) {
$this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
}
}
+
+ // Propagate cache contexts to the config object.
+ $this->propagateCacheableDependencyOverrides($cache_key);
+
return $this->cache[$cache_key];
}
}
@@ -183,6 +187,10 @@ protected function doLoadMultiple(array $names, $immutable = TRUE) {
$this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
}
}
+
+ // Propagate cacheable dependencies to the config object.
+ $this->propagateCacheableDependencyOverrides($cache_key);
+
$list[$name] = $this->cache[$cache_key];
}
}
@@ -210,6 +218,20 @@ protected function loadOverrides(array $names) {
}
/**
+ * Propagates overridden cacheable dependencies to cached config objects.
+ *
+ * @param string $cache_key
+ * The key of the cached config object to update.
+ */
+ protected function propagateCacheableDependencyOverrides($cache_key) {
+ foreach ($this->configFactoryOverrides as $override) {
+ $this->cache[$cache_key]->addCacheContexts($override->getCacheContexts());
+ $this->cache[$cache_key]->addCacheTags($override->getCacheTags());
+ $this->cache[$cache_key]->setCacheMaxAgeIfLower($override->getCacheMaxAge());
+ }
+ }
+
+ /**
* {@inheritdoc}
*/
public function reset($name = NULL) {
diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php
index 56dbc19..7b07c1a 100644
--- a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php
+++ b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php
@@ -7,10 +7,12 @@
namespace Drupal\Core\Config;
+use Drupal\Core\Cache\CacheableDependencyInterface;
+
/**
* Defines the interface for a configuration factory override object.
*/
-interface ConfigFactoryOverrideInterface {
+interface ConfigFactoryOverrideInterface extends CacheableDependencyInterface {
/**
* Returns config overrides.
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index a810dbd..e9432f7 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -193,7 +193,7 @@ public function enable() {
*/
public function disable() {
// An entity was disabled, invalidate its own cache tag.
- Cache::invalidateTags($this->getCacheTags());
+ Cache::invalidateTags($this->getCacheTagsForInvalidation());
return $this->setStatus(FALSE);
}
@@ -409,7 +409,7 @@ public function link($text = NULL, $rel = 'edit-form', array $options = []) {
/**
* {@inheritdoc}
*/
- public function getCacheTags() {
+ public function getCacheTagsForInvalidation() {
// Use cache tags that match the underlying config object's name.
// @see \Drupal\Core\Config\ConfigBase::getCacheTags()
return ['config:' . $this->getConfigDependencyName()];
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 59776aa..2a2de2f 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -187,6 +187,11 @@ protected function doLoadMultiple(array $ids = NULL) {
$records = array();
foreach ($this->configFactory->loadMultiple($names) as $config) {
$records[$config->get($this->idKey)] = $this->overrideFree ? $config->getOriginal(NULL, FALSE) : $config->get();
+
+ // Add cacheability metadata to the record.
+ $records[$config->get($this->idKey)]['cacheContexts'] = $config->getCacheContexts();
+ $records[$config->get($this->idKey)]['cacheTags'] = $config->getCacheTags();
+ $records[$config->get($this->idKey)]['cacheMaxAge'] = $config->getCacheMaxAge();
}
return $this->mapFromStorageRecords($records);
}
diff --git a/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php b/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
index fa1de86..0561df1 100644
--- a/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
+++ b/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
@@ -101,7 +101,7 @@ public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b)
/**
* {@inheritdoc}
*/
- public function getCacheTags() {
+ public function getCacheTagsForInvalidation() {
return ['rendered'];
}
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 9ffa497..4c77b5a 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -8,6 +8,7 @@
namespace Drupal\Core\Entity;
use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\MutableCacheableDependencyTrait;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Unicode;
@@ -24,6 +25,8 @@
*/
abstract class Entity implements EntityInterface {
+ use MutableCacheableDependencyTrait;
+
use DependencySerializationTrait {
__sleep as traitSleep;
}
@@ -440,23 +443,36 @@ public function referencedEntities() {
* {@inheritdoc}
*/
public function getCacheContexts() {
- return [];
+ return $this->cacheContexts;
}
/**
* {@inheritdoc}
*/
- public function getCacheTags() {
+ public function getCacheTagsForInvalidation() {
// @todo Add bundle-specific listing cache tag?
// https://www.drupal.org/node/2145751
+ if ($this->isNew()) {
+ return [];
+ }
return [$this->entityTypeId . ':' . $this->id()];
}
/**
* {@inheritdoc}
*/
+ public function getCacheTags() {
+ if ($this->cacheTags) {
+ return Cache::mergeTags($this->getCacheTagsForInvalidation(), $this->cacheTags);
+ }
+ return $this->getCacheTagsForInvalidation();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getCacheMaxAge() {
- return Cache::PERMANENT;
+ return $this->cacheMaxAge;
}
/**
@@ -511,7 +527,7 @@ protected function invalidateTagsOnSave($update) {
}
if ($update) {
// An existing entity was updated, also invalidate its unique cache tag.
- $tags = Cache::mergeTags($tags, $this->getCacheTags());
+ $tags = Cache::mergeTags($tags, $this->getCacheTagsForInvalidation());
}
Cache::invalidateTags($tags);
}
@@ -532,7 +548,7 @@ protected static function invalidateTagsOnDelete(EntityTypeInterface $entity_typ
// other pages than the one it's on. The one it's on is handled by its own
// cache tag, but subsequent list pages would not be invalidated, hence we
// must invalidate its list cache tags as well.)
- $tags = Cache::mergeTags($tags, $entity->getCacheTags());
+ $tags = Cache::mergeTags($tags, $entity->getCacheTagsForInvalidation());
}
Cache::invalidateTags($tags);
}
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index 6d61d0c..9caaf8d 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -101,6 +101,12 @@ public function buildForm(array $form, FormStateInterface $form_state) {
$this->init($form_state);
}
+ // Ensure that edit forms have the correct cacheability metadata so they can
+ // be cached.
+ if (!$this->entity->isNew()) {
+ \Drupal::service('renderer')->addCacheableDependency($form, $this->entity);
+ }
+
// Retrieve the form array using the possibly updated entity in form state.
$form = $this->form($form, $form_state);
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 68dafd0..2d443d1 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -9,13 +9,14 @@
use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Cache\CacheableDependencyInterface;
+use Drupal\Core\Cache\MutableCacheableDependencyInterface;
/**
* Defines a common interface for all entity objects.
*
* @ingroup entity_api
*/
-interface EntityInterface extends AccessibleInterface, CacheableDependencyInterface {
+interface EntityInterface extends AccessibleInterface, CacheableDependencyInterface, MutableCacheableDependencyInterface {
/**
* Gets the entity UUID (Universally Unique Identifier).
@@ -349,6 +350,20 @@ public function referencedEntities();
public function getOriginalId();
/**
+ * Returns the cache tags that should be used when invalidating caches.
+ *
+ * This will not return additional cache tags added through addCacheTags().
+ * Invalidating caches that are depending on this entity must use this method.
+ *
+ * @return string[]
+ * Set of cache tags.
+ *
+ * @see \Drupal\Core\Cache\MutableCacheableDependencyInterface::addCacheTags()
+ * @see \Drupal\Core\Cache\CacheableDependencyInterface::getCacheTags()
+ */
+ public function getCacheTagsForInvalidation();
+
+ /**
* Sets the original ID.
*
* @param int|string|null $id
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 1e1323e..42e475a 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -969,6 +969,7 @@ public function getTranslationFromContext(EntityInterface $entity, $langcode = N
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
if (empty($langcode)) {
$langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
+ $entity->addCacheContexts(['languages:' . LanguageInterface::TYPE_CONTENT]);
}
// Retrieve language fallback candidates to perform the entity language
diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
index 09736d2..8281eb9 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -117,14 +117,10 @@ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = N
* {@inheritdoc}
*/
public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL) {
- if (!isset($langcode)) {
- $langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
- }
-
$build_list = array(
'#sorted' => TRUE,
'#pre_render' => array(array($this, 'buildMultiple')),
- '#langcode' => $langcode,
+ '#langcode' => $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(),
);
$weight = 0;
foreach ($entities as $key => $entity) {
@@ -133,9 +129,10 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
$entity = $this->entityManager->getTranslationFromContext($entity, $langcode);
// Set build defaults.
- $build_list[$key] = $this->getBuildDefaults($entity, $view_mode, $langcode);
+ $entity_langcode = $entity->language()->getId();
+ $build_list[$key] = $this->getBuildDefaults($entity, $view_mode, $entity_langcode);
$entityType = $this->entityTypeId;
- $this->moduleHandler()->alter(array($entityType . '_build_defaults', 'entity_build_defaults'), $build_list[$key], $entity, $view_mode, $langcode);
+ $this->moduleHandler()->alter(array($entityType . '_build_defaults', 'entity_build_defaults'), $build_list[$key], $entity, $view_mode, $entity_langcode);
$build_list[$key]['#weight'] = $weight++;
}
diff --git a/core/modules/aggregator/src/Entity/Item.php b/core/modules/aggregator/src/Entity/Item.php
index 6986aaa..44f4c15 100644
--- a/core/modules/aggregator/src/Entity/Item.php
+++ b/core/modules/aggregator/src/Entity/Item.php
@@ -225,13 +225,13 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
// handles the regular cases. The Item entity has one special case: a newly
// created Item is *also* associated with a Feed, so we must invalidate the
// associated Feed's cache tag.
- Cache::invalidateTags($this->getCacheTags());
+ Cache::invalidateTags($this->getCacheTagsForInvalidation());
}
/**
* {@inheritdoc}
*/
- public function getCacheTags() {
+ public function getCacheTagsForInvalidation() {
return Feed::load($this->getFeedId())->getCacheTags();
}
diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php
index 948d293..869b544 100644
--- a/core/modules/block/src/Entity/Block.php
+++ b/core/modules/block/src/Entity/Block.php
@@ -246,7 +246,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
// so we must invalidate the associated block's cache tag (which includes
// the theme cache tag).
if (!$update) {
- Cache::invalidateTags($this->getCacheTags());
+ Cache::invalidateTags($this->getCacheTagsForInvalidation());
}
}
diff --git a/core/modules/block/src/Tests/BlockViewBuilderTest.php b/core/modules/block/src/Tests/BlockViewBuilderTest.php
index ccb53e4..7d21775 100644
--- a/core/modules/block/src/Tests/BlockViewBuilderTest.php
+++ b/core/modules/block/src/Tests/BlockViewBuilderTest.php
@@ -194,7 +194,7 @@ public function testBlockViewBuilderAlter() {
// Enable the block view alter hook that adds a suffix, for basic testing.
\Drupal::state()->set('block_test_view_alter_suffix', TRUE);
- Cache::invalidateTags($this->block->getCacheTags());
+ Cache::invalidateTags($this->block->getCacheTagsForInvalidation());
$build = $this->getBlockRenderArray();
$this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '
Goodbye!', 'A block with content is altered.');
$this->assertIdentical($this->renderer->renderRoot($build), 'Llamas > unicorns!
Goodbye!');
@@ -206,7 +206,7 @@ public function testBlockViewBuilderAlter() {
$request->setMethod('GET');
\Drupal::state()->set('block_test.content', NULL);
- Cache::invalidateTags($this->block->getCacheTags());
+ Cache::invalidateTags($this->block->getCacheTagsForInvalidation());
$default_keys = array('entity_view', 'block', 'test_block');
$default_tags = array('block_view', 'config:block.block.test_block');
diff --git a/core/modules/comment/src/CommentViewBuilder.php b/core/modules/comment/src/CommentViewBuilder.php
index 6923220..66bb193 100644
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -71,11 +71,9 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco
->getFieldDefinition($entity->getFieldName())
->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED;
// If threading is enabled, don't render cache individual comments, but do
- // keep the cache tags, so they can bubble up.
+ // keep the cacheability metadata, so it can bubble up.
if ($build['#comment_threaded']) {
- $cache_tags = $build['#cache']['tags'];
- $build['#cache'] = [];
- $build['#cache']['tags'] = $cache_tags;
+ unset($build['#cache']['keys']);
}
return $build;
diff --git a/core/modules/comment/src/Tests/CommentTranslationUITest.php b/core/modules/comment/src/Tests/CommentTranslationUITest.php
index cfb63c8..dc1bf9e 100644
--- a/core/modules/comment/src/Tests/CommentTranslationUITest.php
+++ b/core/modules/comment/src/Tests/CommentTranslationUITest.php
@@ -33,6 +33,18 @@ class CommentTranslationUITest extends ContentTranslationUITestBase {
protected $adminUser;
/**
+ * {inheritdoc}
+ */
+ protected $defaultCacheContexts = [
+ 'languages:language_interface',
+ 'theme',
+ 'user.permissions',
+ 'timezone',
+ 'url.query_args.pagers:0',
+ 'user.roles'
+ ];
+
+ /**
* Modules to install.
*
* @var array
diff --git a/core/modules/config/src/Tests/CacheContextConfigOverrideTest.php b/core/modules/config/src/Tests/CacheContextConfigOverrideTest.php
new file mode 100644
index 0000000..4782a51
--- /dev/null
+++ b/core/modules/config/src/Tests/CacheContextConfigOverrideTest.php
@@ -0,0 +1,73 @@
+installEntitySchema('block_content');
+ $this->installConfig(['config_override_test']);
+ }
+
+ public function testConfigOverride() {
+ // It's pirate day today!
+ $GLOBALS['it_is_pirate_day'] = TRUE;
+
+ $config_factory = $this->container->get('config.factory');
+ $config = $config_factory->get('system.theme');
+
+ // Check that we are using the Pirate theme.
+ $theme = $config->get('default');
+ $this->assertEqual('pirate', $theme);
+
+ // Check that the cacheable properties are correct.
+ $this->assertEqual(['pirate_day'], $config->getCacheContexts());
+ $this->assertEqual(['config:system.theme', 'pirate-day-tag'], $config->getCacheTags());
+ $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $config->getCacheMaxAge());
+
+ // Load the User login block and check that its cacheability metadata is
+ // overridden correctly. This ensures that the metadata is correctly applied
+ // to config entities.
+ /** @var EntityManagerInterface $entity_manager */
+ $entity_manager = $this->container->get('entity.manager');
+ $block = $entity_manager->getStorage('block')->load('call_to_action');
+
+ // Check that our call to action message is appealing to filibusters.
+ $this->assertEqual($block->label(), 'Draw yer cutlasses!');
+
+ // Check that the cacheability metadata properties are correct.
+ $this->assertEqual(['pirate_day'], $block->getCacheContexts());
+ $this->assertEqual(['config:block.block.call_to_action', 'pirate-day-tag'], $block->getCacheTags());
+ $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $block->getCacheMaxAge());
+ }
+
+}
diff --git a/core/modules/config/tests/config_entity_static_cache_test/src/ConfigOverrider.php b/core/modules/config/tests/config_entity_static_cache_test/src/ConfigOverrider.php
index 2867c7d..8dad5bb 100644
--- a/core/modules/config/tests/config_entity_static_cache_test/src/ConfigOverrider.php
+++ b/core/modules/config/tests/config_entity_static_cache_test/src/ConfigOverrider.php
@@ -7,6 +7,7 @@
namespace Drupal\config_entity_static_cache_test;
+use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\ConfigFactoryOverrideInterface;
use Drupal\Core\Config\StorageInterface;
@@ -40,4 +41,25 @@ public function createConfigObject($name, $collection = StorageInterface::DEFAUL
return NULL;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheContexts() {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheTags() {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheMaxAge() {
+ return Cache::PERMANENT;
+ }
+
}
diff --git a/core/modules/config/tests/config_override_test/config/install/block.block.call_to_action.yml b/core/modules/config/tests/config_override_test/config/install/block.block.call_to_action.yml
new file mode 100644
index 0000000..8951c0d
--- /dev/null
+++ b/core/modules/config/tests/config_override_test/config/install/block.block.call_to_action.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - block_content
+ theme:
+ - classy
+id: call_to_action
+theme: classy
+region: content
+weight: null
+provider: null
+plugin: 'block_content:d7c9d8ba-663f-41b4-8756-86bc55c44653'
+settings:
+ id: 'block_content:d7c9d8ba-663f-41b4-8756-86bc55c44653'
+ label: 'Shop for cheap now!'
+ provider: block_content
+ label_display: visible
+ status: true
+ info: ''
+ view_mode: default
+visibility:
+ request_path:
+ id: request_path
+ pages: ''
+ negate: false
diff --git a/core/modules/config/tests/config_override_test/config_override_test.services.yml b/core/modules/config/tests/config_override_test/config_override_test.services.yml
index c3fae64..886b7fd 100644
--- a/core/modules/config/tests/config_override_test/config_override_test.services.yml
+++ b/core/modules/config/tests/config_override_test/config_override_test.services.yml
@@ -1,4 +1,8 @@
services:
+ cache_context.pirate_day:
+ class: Drupal\config_override_test\Cache\PirateDayCacheContext
+ tags:
+ - { name: cache.context }
config_override_test.overrider:
class: Drupal\config_override_test\ConfigOverrider
tags:
@@ -7,3 +11,7 @@ services:
class: Drupal\config_override_test\ConfigOverriderLowPriority
tags:
- { name: config.factory.override, priority: -100 }
+ config_override_test.pirate_day_cache_context_overrider:
+ class: Drupal\config_override_test\PirateDayCacheContextConfigOverride
+ tags:
+ - { name: config.factory.override }
diff --git a/core/modules/config/tests/config_override_test/src/Cache/PirateDayCacheContext.php b/core/modules/config/tests/config_override_test/src/Cache/PirateDayCacheContext.php
new file mode 100644
index 0000000..80e6000
--- /dev/null
+++ b/core/modules/config/tests/config_override_test/src/Cache/PirateDayCacheContext.php
@@ -0,0 +1,52 @@
+ ['default' => 'pirate']];
+ }
+ if (in_array('block.block.call_to_action', $names)) {
+ $overrides = $overrides + [
+ 'block.block.call_to_action' => [
+ 'settings' => ['label' => 'Draw yer cutlasses!'],
+ ],
+ ];
+ }
+ }
+
+ return $overrides;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheSuffix() {
+ return 'PirateDayConfigOverrider';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) {
+ return NULL;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheContexts() {
+ return ['pirate_day'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheTags() {
+ return ['pirate-day-tag'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheMaxAge() {
+ return PirateDayCacheContext::PIRATE_DAY_MAX_AGE;
+ }
+
+}
diff --git a/core/modules/contact/src/Tests/Views/ContactLinkTest.php b/core/modules/contact/src/Tests/Views/ContactLinkTest.php
index 4c82d18..a4db76e 100644
--- a/core/modules/contact/src/Tests/Views/ContactLinkTest.php
+++ b/core/modules/contact/src/Tests/Views/ContactLinkTest.php
@@ -86,7 +86,7 @@ public function testContactLink() {
// Disable contact link for no_contact.
$this->userData->set('contact', $no_contact_account->id(), 'enabled', FALSE);
// @todo Remove cache invalidation in https://www.drupal.org/node/2477903.
- Cache::invalidateTags($no_contact_account->getCacheTags());
+ Cache::invalidateTags($no_contact_account->getCacheTagsForInvalidation());
$this->drupalGet('test-contact-link');
$this->assertContactLinks($accounts, array('root', 'admin'));
}
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
index e524359..5faa85c 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
@@ -7,18 +7,22 @@
namespace Drupal\content_translation\Tests;
+use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Component\Utility\SafeMarkup;
+use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests the Content Translation UI.
*/
abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
+ use AssertPageCacheContextsAndTagsTrait;
+
/**
* The id of the entity being translated.
*
@@ -34,6 +38,15 @@
protected $testLanguageSelector = TRUE;
/**
+ * Default cache contexts expected on a non-translated entity.
+ *
+ * Cache contexts will not be checked if this list is empty.
+ *
+ * @var string[]
+ */
+ protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user.permissions'];
+
+ /**
* Tests the basic translation UI.
*/
function testTranslationUI() {
@@ -64,6 +77,11 @@ protected function doTestBasicTranslation() {
$this->assertTrue($entity, 'Entity found in the database.');
$this->drupalGet($entity->urlInfo());
$this->assertResponse(200, 'Entity URL is valid.');
+
+ // Ensure that the content language cache context is not yet added to the
+ // page.
+ $this->assertCacheContexts($this->defaultCacheContexts);
+
$this->drupalGet($entity->urlInfo('drupal:content-translation-overview'));
$this->assertNoText('Source language', 'Source language column correctly hidden.');
@@ -87,9 +105,14 @@ protected function doTestBasicTranslation() {
], array('language' => $language));
$this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode));
- // Get the entity and reset its cache, so that the new translation gets the
- // updated values.
+ // Ensure that the content language cache context is not yet added to the
+ // page.
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
+ $this->drupalGet($entity->urlInfo());
+ $this->assertCacheContexts(Cache::mergeContexts(['languages:language_content'], $this->defaultCacheContexts));
+
+ // Reset the cache of the entity, so that the new translation gets the
+ // updated values.
$metadata_source_translation = $this->manager->getTranslationMetadata($entity->getTranslation($default_langcode));
$metadata_target_translation = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php
index a05d3a8..1ed79b6 100644
--- a/core/modules/image/src/Entity/ImageStyle.php
+++ b/core/modules/image/src/Entity/ImageStyle.php
@@ -267,7 +267,7 @@ public function flush($path = NULL) {
// Clear caches so that formatters may be added for this style.
drupal_theme_rebuild();
- Cache::invalidateTags($this->getCacheTags());
+ Cache::invalidateTags($this->getCacheTagsForInvalidation());
return $this;
}
diff --git a/core/modules/language/src/Config/LanguageConfigFactoryOverride.php b/core/modules/language/src/Config/LanguageConfigFactoryOverride.php
index 3d0a67b..e2e8c3b 100644
--- a/core/modules/language/src/Config/LanguageConfigFactoryOverride.php
+++ b/core/modules/language/src/Config/LanguageConfigFactoryOverride.php
@@ -7,6 +7,7 @@
namespace Drupal\language\Config;
+use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\ConfigCollectionInfo;
use Drupal\Core\Config\ConfigCrudEvent;
use Drupal\Core\Config\ConfigFactoryOverrideBase;
@@ -222,4 +223,25 @@ public function onConfigDelete(ConfigCrudEvent $event) {
}
}
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheContexts() {
+ return ['languages:language_interface'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheTags() {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheMaxAge() {
+ return Cache::PERMANENT;
+ }
+
}
diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php
index b068808..615da6b 100644
--- a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php
+++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php
@@ -18,6 +18,11 @@
class MenuLinkContentTranslationUITest extends ContentTranslationUITestBase {
/**
+ * {inheritdoc}
+ */
+ protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user.permissions', 'user.roles:authenticated'];
+
+ /**
* Modules to enable.
*
* @var array
diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php
index 287920b..c392750 100644
--- a/core/modules/node/src/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/src/Tests/NodeTranslationUITest.php
@@ -22,6 +22,21 @@
class NodeTranslationUITest extends ContentTranslationUITestBase {
/**
+ * {inheritdoc}
+ */
+ protected $defaultCacheContexts = [
+ 'languages:language_interface',
+ 'theme',
+ 'user.permissions',
+ 'route.menu_active_trails:account',
+ 'route.menu_active_trails:footer',
+ 'route.menu_active_trails:main',
+ 'route.menu_active_trails:tools',
+ 'timezone',
+ 'user.roles'
+ ];
+
+ /**
* Modules to enable.
*
* @var array
diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php
index a2179f9..29a18f4 100644
--- a/core/modules/shortcut/src/Entity/Shortcut.php
+++ b/core/modules/shortcut/src/Entity/Shortcut.php
@@ -102,7 +102,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
// newly created shortcut is *also* added to a shortcut set, so we must
// invalidate the associated shortcut set's cache tag.
if (!$update) {
- Cache::invalidateTags($this->getCacheTags());
+ Cache::invalidateTags($this->getCacheTagsForInvalidation());
}
}
@@ -178,7 +178,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
/**
* {@inheritdoc}
*/
- public function getCacheTags() {
+ public function getCacheTagsForInvalidation() {
return $this->shortcut_set->entity->getCacheTags();
}
diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
index 3fc8232..e324d80 100644
--- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
@@ -19,6 +19,11 @@
class ShortcutTranslationUITest extends ContentTranslationUITestBase {
/**
+ * {inheritdoc}
+ */
+ protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user'];
+
+ /**
* Modules to enable.
*
* @var array
diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
index 0b365cb..6472cb0 100644
--- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
+++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
@@ -571,7 +571,7 @@ public function testReferencedEntity() {
// a cache miss for every route except the ones for the non-referencing
// entity and the empty entity listing.
$this->pass("Test invalidation of referenced entity's cache tag.", 'Debug');
- Cache::invalidateTags($this->entity->getCacheTags());
+ Cache::invalidateTags($this->entity->getCacheTagsForInvalidation());
$this->verifyPageCache($referencing_entity_url, 'MISS');
$this->verifyPageCache($listing_url, 'MISS');
$this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
diff --git a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
index 0b6f430..5ef3660 100644
--- a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
+++ b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
@@ -121,7 +121,7 @@ public function testEntityUri() {
// Verify that after invalidating the entity's cache tag directly, there is
// a cache miss.
$this->pass("Test invalidation of entity's cache tag.", 'Debug');
- Cache::invalidateTags($this->entity->getCacheTags());
+ Cache::invalidateTags($this->entity->getCacheTagsForInvalidation());
$this->verifyPageCache($entity_url, 'MISS');
// Verify a cache hit.
diff --git a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
index 06a18e3..5ba6bcd 100644
--- a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
+++ b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
@@ -153,7 +153,7 @@ public function cacheGet($type) {
* Clear out cached data for a view.
*/
public function cacheFlush() {
- Cache::invalidateTags($this->view->storage->getCacheTags());
+ Cache::invalidateTags($this->view->storage->getCacheTagsForInvalidation());
}
/**
diff --git a/core/modules/views/src/Tests/Plugin/CacheTagTest.php b/core/modules/views/src/Tests/Plugin/CacheTagTest.php
index 3d497d5..309a856 100644
--- a/core/modules/views/src/Tests/Plugin/CacheTagTest.php
+++ b/core/modules/views/src/Tests/Plugin/CacheTagTest.php
@@ -197,7 +197,7 @@ public function testTagCaching() {
$view->destroy();
// Invalidate the views cache tags in order to invalidate the render
// caching.
- \Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTags());
+ \Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTagsForInvalidation());
$build = $view->buildRenderable();
$renderer->renderPlain($build);
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 05451be..b7d3aa5 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -1336,4 +1336,32 @@ public function hasTrustedData() {
return $this->storage->hasTrustedData();
}
+ /**
+ * {@inheritdoc}
+ */
+ public function addCacheContexts(array $cache_contexts) {
+ return $this->storage->addCacheContexts($cache_contexts);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setCacheMaxAgeIfLower($max_age) {
+ return $this->storage->setCacheMaxAgeIfLower($max_age);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheTagsForInvalidation() {
+ return $this->storage->getCacheTagsForInvalidation();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addCacheTags(array $cache_tags) {
+ return $this->storage->addCacheTags($cache_tags);
+ }
+
}