.../Drupal/Core/Config/Entity/ConfigEntityBase.php | 3 ++ core/lib/Drupal/Core/Entity/Entity.php | 34 ++++++++++++++++ core/lib/Drupal/Core/Entity/EntityInterface.php | 19 +++++++++ core/lib/Drupal/Core/Entity/EntityViewBuilder.php | 23 ++++++----- .../Core/Entity/EntityViewBuilderInterface.php | 11 +++++ .../block/lib/Drupal/block/BlockViewBuilder.php | 27 +++---------- .../comment/Tests/Entity/CommentLockTest.php | 8 ++++ core/modules/filter/filter.module | 1 - .../lib/Drupal/filter/Entity/FilterFormat.php | 8 +--- .../node/lib/Drupal/node/Entity/NodeType.php | 11 ----- .../system/lib/Drupal/system/Entity/Menu.php | 19 --------- .../Tests/Entity/EntityCacheTagsTestBase.php | 2 +- core/modules/user/lib/Drupal/user/Entity/Role.php | 13 ------ .../user/lib/Drupal/user/PermissionsHash.php | 2 +- .../modules/views/lib/Drupal/views/Entity/View.php | 14 +------ .../views_ui/lib/Drupal/views_ui/ViewUI.php | 14 +++++++ .../Config/Entity/ConfigEntityBaseUnitTest.php | 16 ++++++++ .../Drupal/Tests/Core/Entity/EntityUnitTest.php | 42 ++++++++++++++++++-- 18 files changed, 166 insertions(+), 101 deletions(-) diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php index 492876a..9d01118 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config\Entity; use Drupal\Component\Utility\String; +use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Entity; use Drupal\Core\Config\ConfigDuplicateUUIDException; use Drupal\Core\Entity\EntityStorageControllerInterface; @@ -155,6 +156,8 @@ public function enable() { * {@inheritdoc} */ public function disable() { + // An entity was disabled, invalidate its own cache tag. + Cache::invalidateTags(array($this->entityTypeId => array($this->id()))); return $this->setStatus(FALSE); } diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 2bddb37..f992706 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Entity; +use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Cache\Cache; use Drupal\Core\DependencyInjection\DependencySerialization; use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; @@ -347,9 +349,18 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { */ public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { $this->onSaveOrDelete(); + + // An entity was created or updated: invalidate its list cache tags. (An + // updated entity may start to appear in a listing because it now meets that + // listing's filtering requirements. A newly created entity may start to + // appear in listings because it did not exist before.) + $tags = $this->getListCacheTags(); if ($update) { + // An existing entity was updated, also invalidate its unique cache tag. + $tags = NestedArray::mergeDeep($tags, $this->getCacheTag()); $this->onUpdateBundleEntity(); } + Cache::invalidateTags($tags); } /** @@ -374,9 +385,17 @@ public static function preDelete(EntityStorageControllerInterface $storage_contr * {@inheritdoc} */ public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) { + $tags = array(); foreach ($entities as $entity) { + // An entity was deleted: invalidate its own cache tag, but also its list + // cache tags. (A deleted entity may cause changes in a paged list on + // 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 = NestedArray::mergeDeepArray(array($tags, $entity->getCacheTag(), $entity->getListCacheTags())); $entity->onSaveOrDelete(); } + Cache::invalidateTags($tags); } /** @@ -393,6 +412,21 @@ public function referencedEntities() { } /** + * {@inheritdoc} + */ + public function getCacheTag() { + return array($this->entityTypeId => array($this->id())); + } + + /** + * {@inheritdoc} + */ + public function getListCacheTags() { + // @todo Add bundle-specific listing cache tag? https://drupal.org/node/2145751 + return array($this->entityTypeId . 's' => TRUE); + } + + /** * Acts on an entity after it was saved or deleted. */ protected function onSaveOrDelete() { diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index ce4909a..a2a43ae 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -319,4 +319,23 @@ public function getOriginalId(); */ public function setOriginalId($id); + /** + * The unique cache tag associated with this entity. + * + * @return array + * An array of cache tags. + */ + public function getCacheTag(); + + /** + * The list cache tags associated with this entity. + * + * Enables code listing entities of this type to ensure that newly created + * entities show up immediately. + * + * @return array + * An array of cache tags. + */ + public function getListCacheTags(); + } diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 2e48ecc..187c4c7 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Entity; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Field\FieldItemInterface; @@ -147,11 +148,8 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco '#view_mode' => $view_mode, '#langcode' => $langcode, '#cache' => array( - 'tags' => array( - $this->entityTypeId . '_view' => TRUE, - $this->entityTypeId => array($entity->id()), - ), - ) + 'tags' => NestedArray::mergeDeep($this->getCacheTag(), $entity->getCacheTag()), + ), ); // Cache the rendered output if permitted by the view mode and global entity @@ -276,14 +274,12 @@ public function resetCache(array $entities = NULL) { if (isset($entities)) { $tags = array(); foreach ($entities as $entity) { - $id = $entity->id(); - $tags[$this->entityTypeId][$id] = $id; - $tags[$this->entityTypeId . '_view_' . $entity->bundle()] = TRUE; + $tags = NestedArray::mergeDeep($tags, $entity->getCacheTag()); } - Cache::deleteTags($tags); + Cache::invalidateTags($tags); } else { - Cache::deleteTags(array($this->entityTypeId . '_view' => TRUE)); + Cache::invalidateTags($this->getCacheTag()); } } @@ -366,4 +362,11 @@ protected function isViewModeCacheable($view_mode) { return !empty($view_modes_info[$view_mode]['cache']); } + /** + * {@inheritdoc} + */ + public function getCacheTag() { + return array($this->entityTypeId . '_view' => TRUE); + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php index b41848b..aee9588 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php @@ -149,4 +149,15 @@ public function viewField(FieldItemListInterface $items, $display_options = arra */ public function viewFieldItem(FieldItemInterface $item, $display_options = array()); + /** + * The cache tag associated with this entity view builder. + * + * An entity view builder is instantiated on a per-entity type basis, so the + * cache tags are also per-entity type. + * + * @return array + * An array of cache tags. + */ + public function getCacheTag(); + } diff --git a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php index a6a925a..85bbbcf 100644 --- a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php +++ b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php @@ -68,15 +68,12 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la ); $build[$entity_id]['#configuration']['label'] = check_plain($configuration['label']); - // Set cache tags; these always need to be set, whether the block is - // cacheable or not, so that the page cache is correctly informed. - $default_cache_tags = array( - 'content' => TRUE, - 'block_view' => TRUE, - 'block' => array($entity->id()), - ); - $build[$entity_id]['#cache']['tags'] = NestedArray::mergeDeep($default_cache_tags, $plugin->getCacheTags()); - + $build[$entity_id]['#cache']['tags'] = NestedArray::mergeDeepArray(array( + array('content' => TRUE), + $this->getCacheTag(), // Block view builder cache tag. + $entity->getCacheTag(), // Block entity cache tag. + $plugin->getCacheTags(), // Block plugin cache tags. + )); if ($plugin->isCacheable()) { $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock'); @@ -155,16 +152,4 @@ public function buildBlock($build) { return $build; } - /** - * {@inheritdoc} - */ - public function resetCache(array $entities = NULL) { - if (isset($entities)) { - Cache::invalidateTags(array('block' => array_keys($entities))); - } - else { - Cache::invalidateTags(array('block_view' => TRUE)); - } - } - } diff --git a/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php b/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php index 1d54be4..48010ec 100644 --- a/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php +++ b/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php @@ -35,6 +35,8 @@ public function testLocks() { $container = new ContainerBuilder(); $container->set('module_handler', $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface')); $container->set('current_user', $this->getMock('Drupal\Core\Session\AccountInterface')); + $container->set('cache.test', $this->getMock('Drupal\Core\Cache\CacheBackendInterface')); + $container->setParameter('cache_bins', array('cache.test' => 'test')); $container->register('request', 'Symfony\Component\HttpFoundation\Request'); $lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface'); $cid = 2; @@ -78,6 +80,12 @@ public function testLocks() { ->method('get') ->with('status') ->will($this->returnValue((object) array('value' => NULL))); + $comment->expects($this->once()) + ->method('getCacheTag') + ->will($this->returnValue(array('comment' => array($cid)))); + $comment->expects($this->once()) + ->method('getListCacheTags') + ->will($this->returnValue(array('comments' => TRUE))); $storage_controller = $this->getMock('Drupal\comment\CommentStorageControllerInterface'); $comment->preSave($storage_controller); $comment->postSave($storage_controller); diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module index 9c166e5..75a8b36 100644 --- a/core/modules/filter/filter.module +++ b/core/modules/filter/filter.module @@ -195,7 +195,6 @@ function filter_formats(AccountInterface $account = NULL) { * @see filter_formats() */ function filter_formats_reset() { - Cache::deleteTags(array('filter_formats' => TRUE)); drupal_static_reset('filter_formats'); } diff --git a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php index 8e0aadd..cf7673c 100644 --- a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php +++ b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php @@ -7,7 +7,6 @@ namespace Drupal\filter\Entity; -use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Config\Entity\EntityWithPluginBagInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; @@ -196,7 +195,6 @@ public function disable() { // Clear the filter cache whenever a text format is disabled. filter_formats_reset(); - Cache::deleteTags(array('filter_format' => $this->format)); return $this; } @@ -234,11 +232,7 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $ // Clear the static caches of filter_formats() and others. filter_formats_reset(); - if ($update) { - // Clear the filter cache whenever a text format is updated. - Cache::deleteTags(array('filter_format' => $this->id())); - } - else { + if (!$update) { // Default configuration of modules and installation profiles is allowed // to specify a list of user roles to grant access to for the new format; // apply the defined user role permissions when a new format is inserted diff --git a/core/modules/node/lib/Drupal/node/Entity/NodeType.php b/core/modules/node/lib/Drupal/node/Entity/NodeType.php index b187c75..bfe7014 100644 --- a/core/modules/node/lib/Drupal/node/Entity/NodeType.php +++ b/core/modules/node/lib/Drupal/node/Entity/NodeType.php @@ -8,7 +8,6 @@ namespace Drupal\node\Entity; use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\node\NodeTypeInterface; @@ -157,9 +156,6 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $ parent::postSave($storage_controller, $update); if (!$update) { - // Clear the node type cache, so the new type appears. - Cache::deleteTags(array('node_types' => TRUE)); - entity_invoke_bundle_hook('create', 'node', $this->id()); // Create a body if the create_body property is true and we're not in @@ -170,9 +166,6 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $ } } elseif ($this->getOriginalId() != $this->id()) { - // Clear the node type cache to reflect the rename. - Cache::deleteTags(array('node_types' => TRUE)); - $update_count = node_type_update_nodes($this->getOriginalId(), $this->id()); if ($update_count) { drupal_set_message(format_plural($update_count, @@ -185,10 +178,6 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $ } entity_invoke_bundle_hook('rename', 'node', $this->getOriginalId(), $this->id()); } - else { - // Invalidate the cache tag of the updated node type only. - Cache::invalidateTags(array('node_type' => $this->id())); - } } /** diff --git a/core/modules/system/lib/Drupal/system/Entity/Menu.php b/core/modules/system/lib/Drupal/system/Entity/Menu.php index 8dadc1c..64a8e76 100644 --- a/core/modules/system/lib/Drupal/system/Entity/Menu.php +++ b/core/modules/system/lib/Drupal/system/Entity/Menu.php @@ -7,7 +7,6 @@ namespace Drupal\system\Entity; -use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\system\MenuInterface; @@ -81,22 +80,4 @@ public function isLocked() { return (bool) $this->locked; } - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { - parent::postSave($storage_controller, $update); - - Cache::invalidateTags(array('menu' => $this->id())); - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) { - parent::postDelete($storage_controller, $entities); - - Cache::invalidateTags(array('menu' => array_keys($entities))); - } - } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php index f1a0c84..3eab3a8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php @@ -220,7 +220,7 @@ public function testReferencedEntity() { 'entity_test:' . $this->referencing_entity->id(), // Includes the main entity's cache tags, since this entity references it. $cache_tag, - $view_cache_tag + $view_cache_tag, ); $non_referencing_entity_cache_tags = array( 'entity_test_view:1', diff --git a/core/modules/user/lib/Drupal/user/Entity/Role.php b/core/modules/user/lib/Drupal/user/Entity/Role.php index 0ce5186..92c53a5 100644 --- a/core/modules/user/lib/Drupal/user/Entity/Role.php +++ b/core/modules/user/lib/Drupal/user/Entity/Role.php @@ -7,7 +7,6 @@ namespace Drupal\user\Entity; -use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\user\RoleInterface; @@ -134,20 +133,8 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { parent::postSave($storage_controller, $update); - Cache::invalidateTags(array('role' => $this->id())); // Clear render cache. entity_render_cache_clear(); } - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) { - parent::postDelete($storage_controller, $entities); - - $ids = array_keys($entities); - $storage_controller->deleteRoleReferences($ids); - Cache::invalidateTags(array('role' => $ids)); - } - } diff --git a/core/modules/user/lib/Drupal/user/PermissionsHash.php b/core/modules/user/lib/Drupal/user/PermissionsHash.php index 3c6fe87..1fed13e 100644 --- a/core/modules/user/lib/Drupal/user/PermissionsHash.php +++ b/core/modules/user/lib/Drupal/user/PermissionsHash.php @@ -58,7 +58,7 @@ public function generate(AccountInterface $account) { } else { $permissions_hash = $this->doGenerate($sorted_roles); - $this->cache->set("user_permissions_hash:$role_list", $permissions_hash, Cache::PERMANENT, array('role' => $sorted_roles)); + $this->cache->set("user_permissions_hash:$role_list", $permissions_hash, Cache::PERMANENT, array('user_role' => $sorted_roles)); } return $permissions_hash; diff --git a/core/modules/views/lib/Drupal/views/Entity/View.php b/core/modules/views/lib/Drupal/views/Entity/View.php index 097059a..712e719 100644 --- a/core/modules/views/lib/Drupal/views/Entity/View.php +++ b/core/modules/views/lib/Drupal/views/Entity/View.php @@ -7,7 +7,6 @@ namespace Drupal\views\Entity; -use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\views\Views; @@ -305,10 +304,7 @@ public function calculateDependencies() { public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { parent::postSave($storage_controller, $update); - // Clear cache tags for this view. // @todo Remove if views implements a view_builder controller. - $id = $this->id(); - Cache::deleteTags(array('view' => array($id => $id))); views_invalidate_cache(); } @@ -359,17 +355,9 @@ public static function postDelete(EntityStorageControllerInterface $storage_cont parent::postDelete($storage_controller, $entities); $tempstore = \Drupal::service('user.tempstore')->get('views'); - $tags = array(); - foreach ($entities as $entity) { - $id = $entity->id(); - $tempstore->delete($id); - $tags['view'][$id] = $id; + $tempstore->delete($entity->id()); } - - // Clear cache tags for these views. - // @todo Remove if views implements a view_builder controller. - Cache::deleteTags($tags); } /** diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php index 009e8e4..80fe7b3 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php @@ -1212,4 +1212,18 @@ public function calculateDependencies() { public function getConfigDependencyName() { } + /** + * {@inheritdoc} + */ + public function getCacheTag() { + $this->storage->getCacheTag(); + } + + /** + * {@inheritdoc} + */ + public function getListCacheTags() { + $this->storage->getListCacheTags(); + } + } diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php index 9deeaa6..97ba84b 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php @@ -78,6 +78,13 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { protected $id; /** + * The mocked cache backend. + * + * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheBackend; + + /** * {@inheritdoc} */ public static function getInfo() { @@ -119,10 +126,14 @@ public function setUp() { ->with('en') ->will($this->returnValue(new Language(array('id' => 'en')))); + $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); + $container->set('cache.test', $this->cacheBackend); + $container->setParameter('cache_bins', array('cache.test' => 'test')); \Drupal::setContainer($container); $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array($values, $this->entityTypeId)); @@ -325,6 +336,10 @@ public function testEnable() { * @depends testSetStatus */ public function testDisable() { + $this->cacheBackend->expects($this->once()) + ->method('invalidateTags') + ->with(array($this->entityTypeId => array($this->id))); + $this->entity->setStatus(TRUE); $this->assertSame($this->entity, $this->entity->disable()); $this->assertFalse($this->entity->status()); @@ -415,6 +430,7 @@ public function testToArray() { $this->assertSame($this->entity->get($name), $properties[$name]); } } + } class TestConfigurablePlugin extends PluginBase implements ConfigurablePluginInterface { diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php index be09ad8..c874f9a 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php @@ -68,6 +68,13 @@ class EntityUnitTest extends UnitTestCase { protected $languageManager; /** + * The mocked cache backend. + * + * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheBackend; + + /** * The entity values. * * @var array @@ -112,11 +119,14 @@ public function setUp() { ->with('en') ->will($this->returnValue(new Language(array('id' => 'en')))); + $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); - + $container->set('cache.test', $this->cacheBackend); + $container->setParameter('cache_bins', array('cache.test' => 'test')); \Drupal::setContainer($container); $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\Entity', array($this->values, $this->entityTypeId)); @@ -280,9 +290,26 @@ public function testPreSave() { * @covers ::postSave */ public function testPostSave() { + $this->cacheBackend->expects($this->at(0)) + ->method('invalidateTags') + ->with(array( + $this->entityTypeId . 's' => TRUE, // List cache tag. + )); + $this->cacheBackend->expects($this->at(1)) + ->method('invalidateTags') + ->with(array( + $this->entityTypeId . 's' => TRUE, // List cache tag. + $this->entityTypeId => array($this->values['id']), // Own cache tag. + )); + // This method is internal, so check for errors on calling it only. $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageControllerInterface'); - $this->entity->postSave($storage); + + // A creation should trigger the invalidation of the "list" cache tag. + $this->entity->postSave($storage, FALSE); + // An update should trigger the invalidation of both the "list" and the + // "own" cache tags. + $this->entity->postSave($storage, TRUE); } /** @@ -317,16 +344,23 @@ public function testPreDelete() { * @covers ::postDelete */ public function testPostDelete() { + $this->cacheBackend->expects($this->once()) + ->method('invalidateTags') + ->with(array( + $this->entityTypeId => array($this->values['id']), + $this->entityTypeId . 's' => TRUE, + )); $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageControllerInterface'); $entity = $this->getMockBuilder('\Drupal\Core\Entity\Entity') + ->setConstructorArgs(array($this->values, $this->entityTypeId)) ->setMethods(array('onSaveOrDelete')) - ->disableOriginalConstructor() ->getMock(); $entity->expects($this->once()) ->method('onSaveOrDelete'); - $this->entity->postDelete($storage, array($entity)); + $entities = array($this->values['id'] => $entity); + $this->entity->postDelete($storage, $entities); } /**