diff --git a/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php new file mode 100644 index 0000000..6434dc1 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php @@ -0,0 +1,52 @@ +cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts); + } + + /** + * {@inheritdoc} + */ + public function addCacheTags(array $cache_tags) { + $this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags); + } + + /** + * {@inheritdoc} + */ + public function addCacheMaxAge($max_age) { + $this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age); + } + +} diff --git a/core/lib/Drupal/Core/Cache/RuntimeCacheContextsDependencyInterface.php b/core/lib/Drupal/Core/Cache/RuntimeCacheContextsDependencyInterface.php deleted file mode 100644 index aff94fd..0000000 --- a/core/lib/Drupal/Core/Cache/RuntimeCacheContextsDependencyInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -getCacheTags()); + Cache::invalidateTags($this->getOriginalCacheTags()); return $this->setStatus(FALSE); } diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index e2172c6..7f1034c 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; } @@ -50,13 +53,6 @@ protected $typedData; /** - * Runtime cache contexts. - * - * @var array - */ - protected $runtimeCacheContexts = []; - - /** * Constructs an Entity object. * * @param array $values @@ -447,13 +443,13 @@ public function referencedEntities() { * {@inheritdoc} */ public function getCacheContexts() { - return $this->runtimeCacheContexts; + return $this->cacheContexts; } /** * {@inheritdoc} */ - public function getCacheTags() { + public function getOriginalCacheTags() { // @todo Add bundle-specific listing cache tag? // https://www.drupal.org/node/2145751 if ($this->isNew()) { @@ -465,8 +461,18 @@ public function getCacheTags() { /** * {@inheritdoc} */ + public function getCacheTags() { + if ($this->cacheTags) { + return Cache::mergeTags($this->getOriginalCacheTags(), $this->cacheTags); + } + return $this->getOriginalCacheTags(); + } + + /** + * {@inheritdoc} + */ public function getCacheMaxAge() { - return Cache::PERMANENT; + return $this->cacheMaxAge; } /** @@ -521,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->getOriginalCacheTags()); } Cache::invalidateTags($tags); } @@ -542,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->getOriginalCacheTags()); } Cache::invalidateTags($tags); } @@ -618,11 +624,4 @@ public function getConfigTarget() { return $this->uuid(); } - /** - * {@inheritdoc} - */ - public function addRuntimeCacheContexts(array $cache_contexts) { - $this->runtimeCacheContexts = Cache::mergeContexts($this->runtimeCacheContexts, $cache_contexts); - } - } diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index 495ffaa..b4cf66f 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -9,14 +9,14 @@ use Drupal\Core\Access\AccessibleInterface; use Drupal\Core\Cache\CacheableDependencyInterface; -use Drupal\Core\Cache\RuntimeCacheContextsDependencyInterface; +use Drupal\Core\Cache\MutableCacheableDependencyInterface; /** * Defines a common interface for all entity objects. * * @ingroup entity_api */ -interface EntityInterface extends AccessibleInterface, CacheableDependencyInterface, RuntimeCacheContextsDependencyInterface { +interface EntityInterface extends AccessibleInterface, CacheableDependencyInterface, MutableCacheableDependencyInterface { /** * Gets the entity UUID (Universally Unique Identifier). @@ -350,6 +350,14 @@ public function referencedEntities(); public function getOriginalId(); /** + * Returns the original cache tags of this entity, without mutations. + * + * @return string[] + * List of cache tags. + */ + public function getOriginalCacheTags(); + + /** * Sets the original ID. * * @param int|string|null $id diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 8281eb9..3a71f44 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -370,7 +370,7 @@ public function resetCache(array $entities = NULL) { Cache::invalidateTags($tags); } else { - Cache::invalidateTags($this->getCacheTags()); + Cache::invalidateTags($this->getOriginalCacheTags()); } } diff --git a/core/modules/aggregator/src/Entity/Item.php b/core/modules/aggregator/src/Entity/Item.php index 6986aaa..0badf9a 100644 --- a/core/modules/aggregator/src/Entity/Item.php +++ b/core/modules/aggregator/src/Entity/Item.php @@ -225,7 +225,7 @@ 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->getOriginalCacheTags()); } /** diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php index 948d293..5637785 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->getOriginalCacheTags()); } } diff --git a/core/modules/block/src/Tests/BlockViewBuilderTest.php b/core/modules/block/src/Tests/BlockViewBuilderTest.php index ccb53e4..dc8ce5a 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->getOriginalCacheTags()); $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->getOriginalCacheTags()); $default_keys = array('entity_view', 'block', 'test_block'); $default_tags = array('block_view', 'config:block.block.test_block'); diff --git a/core/modules/contact/src/Tests/Views/ContactLinkTest.php b/core/modules/contact/src/Tests/Views/ContactLinkTest.php index 4c82d18..35a725f 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->getOriginalCacheTags()); $this->drupalGet('test-contact-link'); $this->assertContactLinks($accounts, array('root', 'admin')); } diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php index a05d3a8..927ede1 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->getOriginalCacheTags()); return $this; } diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php index a2179f9..dd553e8 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->getOriginalCacheTags()); } } diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php index 0b365cb..48a19e2 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->getOriginalCacheTags()); $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..bafdef3 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->getOriginalCacheTags()); $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..9e22e61 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->getOriginalCacheTags()); } /** diff --git a/core/modules/views/src/Tests/Plugin/CacheTagTest.php b/core/modules/views/src/Tests/Plugin/CacheTagTest.php index 3d497d5..e4c1684 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->getOriginalCacheTags()); $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 b738d94..ef7ea73 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -1339,8 +1339,29 @@ public function hasTrustedData() { /** * {@inheritdoc} */ - public function addRuntimeCacheContexts(array $cache_contexts) { - $this->storage->addRuntimeCacheContexts($cache_contexts); + public function addCacheContexts(array $cache_contexts) { + $this->storage->addCacheContexts($cache_contexts); + } + + /** + * {@inheritdoc} + */ + public function addCacheMaxAge($max_age) { + $this->storage->addCacheMaxAge($max_age); + } + + /** + * {@inheritdoc} + */ + public function getOriginalCacheTags() { + return $this->storage->getOriginalCacheTags(); + } + + /** + * {@inheritdoc} + */ + public function addCacheTags(array $cache_tags) { + $this->storage->addCacheTags($cache_tags); } }