Issue #2188565 by Wim Leers, Berdir: Test coverage for Comment, Custom Block, Node, Taxonomy Term and User entity cache tags.
parent
e42ac27706
commit
bd732ee75e
|
@ -320,6 +320,9 @@ abstract class Entity implements EntityInterface {
|
||||||
*/
|
*/
|
||||||
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
||||||
$this->onSaveOrDelete();
|
$this->onSaveOrDelete();
|
||||||
|
if ($update) {
|
||||||
|
$this->onUpdateBundleEntity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -381,6 +384,21 @@ abstract class Entity implements EntityInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acts on entities of which this entity is a bundle entity type.
|
||||||
|
*/
|
||||||
|
protected function onUpdateBundleEntity() {
|
||||||
|
// If this entity is a bundle entity type of another entity type, and we're
|
||||||
|
// updating an existing entity, and that other entity type has a view
|
||||||
|
// builder class, then invalidate the render cache of entities for which
|
||||||
|
// this entity is a bundle.
|
||||||
|
$bundle_of = $this->getEntityType()->getBundleOf();
|
||||||
|
$entity_manager = \Drupal::entityManager();
|
||||||
|
if ($bundle_of !== FALSE && $entity_manager->hasController($bundle_of, 'view_builder')) {
|
||||||
|
$entity_manager->getViewBuilder($bundle_of)->resetCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the URL generator.
|
* Wraps the URL generator.
|
||||||
*
|
*
|
||||||
|
|
|
@ -146,19 +146,21 @@ class EntityViewBuilder extends EntityControllerBase implements EntityController
|
||||||
"#{$this->entityTypeId}" => $entity,
|
"#{$this->entityTypeId}" => $entity,
|
||||||
'#view_mode' => $view_mode,
|
'#view_mode' => $view_mode,
|
||||||
'#langcode' => $langcode,
|
'#langcode' => $langcode,
|
||||||
|
'#cache' => array(
|
||||||
|
'tags' => array(
|
||||||
|
$this->entityTypeId . '_view' => TRUE,
|
||||||
|
$this->entityTypeId => array($entity->id()),
|
||||||
|
),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cache the rendered output if permitted by the view mode and global entity
|
// Cache the rendered output if permitted by the view mode and global entity
|
||||||
// type configuration.
|
// type configuration.
|
||||||
if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && $entity->isDefaultRevision() && $this->entityType->isRenderCacheable()) {
|
if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && $entity->isDefaultRevision() && $this->entityType->isRenderCacheable()) {
|
||||||
$return['#cache'] = array(
|
$return['#cache'] += array(
|
||||||
'keys' => array('entity_view', $this->entityTypeId, $entity->id(), $view_mode),
|
'keys' => array('entity_view', $this->entityTypeId, $entity->id(), $view_mode),
|
||||||
'granularity' => DRUPAL_CACHE_PER_ROLE,
|
'granularity' => DRUPAL_CACHE_PER_ROLE,
|
||||||
'bin' => $this->cacheBin,
|
'bin' => $this->cacheBin,
|
||||||
'tags' => array(
|
|
||||||
$this->entityTypeId . '_view' => TRUE,
|
|
||||||
$this->entityTypeId => array($entity->id()),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
|
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\custom_block\Tests\CustomBlockCacheTagsTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\custom_block\Tests;
|
||||||
|
|
||||||
|
use Drupal\system\Tests\Entity\EntityCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the Custom Block entity's cache tags.
|
||||||
|
*/
|
||||||
|
class CustomBlockCacheTagsTest extends EntityCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = array('custom_block');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return parent::generateStandardizedInfo('Custom Block', 'Custom Block');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createEntity() {
|
||||||
|
// Create a "Llama" custom block.
|
||||||
|
$custom_block = entity_create('custom_block', array(
|
||||||
|
'info' => 'Llama',
|
||||||
|
'type' => 'basic',
|
||||||
|
'body' => 'The name "llama" was adopted by European settlers from native Peruvians.',
|
||||||
|
));
|
||||||
|
$custom_block->save();
|
||||||
|
|
||||||
|
return $custom_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\comment\Tests\CommentCacheTagsTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\comment\Tests;
|
||||||
|
|
||||||
|
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the Comment entity's cache tags.
|
||||||
|
*/
|
||||||
|
class CommentCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = array('comment');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return parent::generateStandardizedInfo('Comment', 'Comment');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Give anonymous users permission to view comments, so that we can verify
|
||||||
|
// the cache tags of cached versions of comment pages.
|
||||||
|
$user_role = entity_load('user_role', DRUPAL_ANONYMOUS_RID);
|
||||||
|
$user_role->grantPermission('access comments');
|
||||||
|
$user_role->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createEntity() {
|
||||||
|
// Create a "bar" bundle for the "entity_test" entity type and create.
|
||||||
|
$bundle = 'bar';
|
||||||
|
entity_test_create_bundle($bundle, NULL, 'entity_test');
|
||||||
|
|
||||||
|
// Create a comment field on this bundle.
|
||||||
|
\Drupal::service('comment.manager')->addDefaultField('entity_test', 'bar');
|
||||||
|
|
||||||
|
// Create a "Camelids" test entity.
|
||||||
|
$entity_test = entity_create('entity_test', array(
|
||||||
|
'name' => 'Camelids',
|
||||||
|
'type' => 'bar',
|
||||||
|
));
|
||||||
|
$entity_test->save();
|
||||||
|
|
||||||
|
// Create a "Llama" taxonomy term.
|
||||||
|
$comment = entity_create('comment', array(
|
||||||
|
'subject' => 'Llama',
|
||||||
|
'comment_body' => 'The name "llama" was adopted by European settlers from native Peruvians.',
|
||||||
|
'entity_id' => $entity_test->id(),
|
||||||
|
'entity_type' => 'entity_test',
|
||||||
|
'field_name' => 'comment',
|
||||||
|
'status' => \Drupal\comment\CommentInterface::PUBLISHED,
|
||||||
|
));
|
||||||
|
$comment->save();
|
||||||
|
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ class CommentLockTest extends UnitTestCase {
|
||||||
unset($methods[array_search('preSave', $methods)]);
|
unset($methods[array_search('preSave', $methods)]);
|
||||||
unset($methods[array_search('postSave', $methods)]);
|
unset($methods[array_search('postSave', $methods)]);
|
||||||
$methods[] = 'onSaveOrDelete';
|
$methods[] = 'onSaveOrDelete';
|
||||||
|
$methods[] = 'onUpdateBundleEntity';
|
||||||
$comment = $this->getMockBuilder('Drupal\comment\Entity\Comment')
|
$comment = $this->getMockBuilder('Drupal\comment\Entity\Comment')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
->setMethods($methods)
|
->setMethods($methods)
|
||||||
|
|
|
@ -366,6 +366,15 @@ class FieldConfig extends ConfigEntityBase implements FieldConfigInterface {
|
||||||
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
||||||
// Clear the cache.
|
// Clear the cache.
|
||||||
field_cache_clear();
|
field_cache_clear();
|
||||||
|
|
||||||
|
if ($update) {
|
||||||
|
// Invalidate the render cache for all affected entities.
|
||||||
|
$entity_manager = \Drupal::entityManager();
|
||||||
|
$entity_type = $this->getTargetEntityTypeId();
|
||||||
|
if ($entity_manager->hasController($entity_type, 'view_builder')) {
|
||||||
|
$entity_manager->getViewBuilder($entity_type)->resetCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -361,6 +361,13 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi
|
||||||
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
||||||
// Clear the cache.
|
// Clear the cache.
|
||||||
field_cache_clear();
|
field_cache_clear();
|
||||||
|
|
||||||
|
// Invalidate the render cache for all affected entities.
|
||||||
|
$entity_manager = \Drupal::entityManager();
|
||||||
|
$entity_type = $this->getTargetEntityTypeId();
|
||||||
|
if ($entity_manager->hasController($entity_type, 'view_builder')) {
|
||||||
|
$entity_manager->getViewBuilder($entity_type)->resetCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\menu\Tests\MenuCacheTagsTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\menu\Tests;
|
||||||
|
|
||||||
|
use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the Menu and Menu Link entities' cache tags.
|
||||||
|
*/
|
||||||
|
class MenuCacheTagsTest extends PageCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = array('menu', 'block', 'test_page_test');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return array(
|
||||||
|
'name' => "Menu & Menu link entities cache tags",
|
||||||
|
'description' => "Test the Menu & Menu link entities' cache tags.",
|
||||||
|
'group' => 'Menu',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests cache tags presence and invalidation of the Menu entity.
|
||||||
|
*
|
||||||
|
* Tests the following cache tags:
|
||||||
|
* - "menu:<menu ID>"
|
||||||
|
*/
|
||||||
|
public function testMenuBlock() {
|
||||||
|
$path = 'test-page';
|
||||||
|
|
||||||
|
// Create a Llama menu, add a link to it and place the corresponding block.
|
||||||
|
$menu = entity_create('menu', array(
|
||||||
|
'id' => 'llama',
|
||||||
|
'label' => 'Llama',
|
||||||
|
'description' => 'Description text',
|
||||||
|
));
|
||||||
|
$menu->save();
|
||||||
|
$menu_link = entity_create('menu_link', array(
|
||||||
|
'link_path' => '<front>',
|
||||||
|
'link_title' => 'Vicuña',
|
||||||
|
'menu_name' => 'llama',
|
||||||
|
));
|
||||||
|
$menu_link->save();
|
||||||
|
$block = $this->drupalPlaceBlock('system_menu_block:llama', array('label' => 'Llama', 'module' => 'system', 'region' => 'footer'));
|
||||||
|
|
||||||
|
// Prime the page cache.
|
||||||
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||||
|
$this->verifyPageCache($path, 'HIT', array('content:1', 'menu:llama'));
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the menu, there is a cache miss.
|
||||||
|
$this->pass('Test modification of menu.', 'Debug');
|
||||||
|
$menu->label = 'Awesome llama';
|
||||||
|
$menu->save();
|
||||||
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the menu link, there is a cache miss.
|
||||||
|
$this->pass('Test modification of menu link.', 'Debug');
|
||||||
|
$menu_link->link_title = 'Guanaco';
|
||||||
|
$menu_link->save();
|
||||||
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after adding a menu link, there is a cache miss.
|
||||||
|
$this->pass('Test addition of menu link.', 'Debug');
|
||||||
|
$menu_link_2 = entity_create('menu_link', array(
|
||||||
|
'link_path' => '<front>',
|
||||||
|
'link_title' => 'Alpaca',
|
||||||
|
'menu_name' => 'llama',
|
||||||
|
));
|
||||||
|
$menu_link_2->save();
|
||||||
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after deleting the first menu link, there is a cache miss.
|
||||||
|
$this->pass('Test deletion of menu link.', 'Debug');
|
||||||
|
$menu_link->delete();
|
||||||
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($path, 'HIT', array('content:1', 'menu:llama'));
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after deleting the menu, there is a cache miss.
|
||||||
|
$this->pass('Test deletion of menu.', 'Debug');
|
||||||
|
$menu->delete();
|
||||||
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($path, 'HIT', array('content:1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -478,66 +478,6 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="menu-edit"><a href="' . base_path() . 'admin/structure/menu/manage/tools">Edit menu</a></li></ul>');
|
$this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="menu-edit"><a href="' . base_path() . 'admin/structure/menu/manage/tools">Edit menu</a></li></ul>');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that cache tags are properly set and bubbled up to the page cache.
|
|
||||||
*
|
|
||||||
* Ensures that invalidation of the "menu:<menu name>" cache tags works.
|
|
||||||
*/
|
|
||||||
public function testMenuBlockPageCacheTags() {
|
|
||||||
// Enable page caching.
|
|
||||||
$config = \Drupal::config('system.performance');
|
|
||||||
$config->set('cache.page.use_internal', 1);
|
|
||||||
$config->set('cache.page.max_age', 300);
|
|
||||||
$config->save();
|
|
||||||
|
|
||||||
// Create a Llama menu, add a link to it and place the corresponding block.
|
|
||||||
$menu = entity_create('menu', array(
|
|
||||||
'id' => 'llama',
|
|
||||||
'label' => 'Llama',
|
|
||||||
'description' => 'Description text',
|
|
||||||
));
|
|
||||||
$menu->save();
|
|
||||||
$menu_link = entity_create('menu_link', array(
|
|
||||||
'link_path' => '<front>',
|
|
||||||
'link_title' => 'Vicuña',
|
|
||||||
'menu_name' => 'llama',
|
|
||||||
));
|
|
||||||
$menu_link->save();
|
|
||||||
$block = $this->drupalPlaceBlock('system_menu_block:llama', array('label' => 'Llama', 'module' => 'system', 'region' => 'footer'));
|
|
||||||
|
|
||||||
// Prime the page cache.
|
|
||||||
$this->drupalGet('test-page');
|
|
||||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
|
|
||||||
|
|
||||||
// Verify a cache hit, but also the presence of the correct cache tags.
|
|
||||||
$this->drupalGet('test-page');
|
|
||||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
|
|
||||||
$cid_parts = array(url('test-page', array('absolute' => TRUE)), 'html');
|
|
||||||
$cid = sha1(implode(':', $cid_parts));
|
|
||||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
|
||||||
$this->assertIdentical($cache_entry->tags, array('content:1', 'menu:llama'));
|
|
||||||
|
|
||||||
// The "Llama" menu is modified.
|
|
||||||
$menu->label = 'Awesome llama';
|
|
||||||
$menu->save();
|
|
||||||
|
|
||||||
// Verify that after the modified menu, there is a cache miss.
|
|
||||||
$this->drupalGet('test-page');
|
|
||||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
|
|
||||||
|
|
||||||
// Verify a cache hit.
|
|
||||||
$this->drupalGet('test-page');
|
|
||||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
|
|
||||||
|
|
||||||
// A link in the "Llama" menu is modified.
|
|
||||||
$menu_link->link_title = 'Guanaco';
|
|
||||||
$menu_link->save();
|
|
||||||
|
|
||||||
// Verify that after the modified menu link, there is a cache miss.
|
|
||||||
$this->drupalGet('test-page');
|
|
||||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests menu link bundles.
|
* Tests menu link bundles.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -188,9 +188,6 @@ class NodeType extends ConfigEntityBase implements NodeTypeInterface {
|
||||||
else {
|
else {
|
||||||
// Invalidate the cache tag of the updated node type only.
|
// Invalidate the cache tag of the updated node type only.
|
||||||
Cache::invalidateTags(array('node_type' => $this->id()));
|
Cache::invalidateTags(array('node_type' => $this->id()));
|
||||||
|
|
||||||
// Invalidate the render cache for all nodes.
|
|
||||||
\Drupal::entityManager()->getViewBuilder('node')->resetCache();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\node\Tests\NodeCacheTagsTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\node\Tests;
|
||||||
|
|
||||||
|
use Drupal\Core\Entity\EntityInterface;
|
||||||
|
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the Node entity's cache tags.
|
||||||
|
*/
|
||||||
|
class NodeCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = array('node');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return parent::generateStandardizedInfo('Node', 'Node');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Give anonymous users permission to view nodes, so that we can verify the
|
||||||
|
// cache tags of cached versions of node pages.
|
||||||
|
$user_role = entity_load('user_role', DRUPAL_ANONYMOUS_RID);
|
||||||
|
$user_role->grantPermission('acess content');
|
||||||
|
$user_role->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createEntity() {
|
||||||
|
// Create a "Camelids" node type.
|
||||||
|
entity_create('node_type', array(
|
||||||
|
'name' => 'Camelids',
|
||||||
|
'type' => 'camelids',
|
||||||
|
))->save();
|
||||||
|
|
||||||
|
// Create a "Llama" node.
|
||||||
|
$node = entity_create('node', array('type' => 'camelids'));
|
||||||
|
$node->setTitle('Llama')
|
||||||
|
->setPublished(TRUE)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getAdditionalCacheTagsForEntity(EntityInterface $node) {
|
||||||
|
return array('user:' . $node->getOwnerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,98 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Contains \Drupal\node\Tests\NodePageCacheTest.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Drupal\node\Tests;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the cache invalidation of node operations.
|
|
||||||
*/
|
|
||||||
class NodePageCacheTest extends NodeTestBase {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An admin user with administrative permissions for nodes.
|
|
||||||
*
|
|
||||||
* @var \Drupal\user\UserInterface
|
|
||||||
*/
|
|
||||||
protected $adminUser;
|
|
||||||
|
|
||||||
public static $modules = array('views');
|
|
||||||
|
|
||||||
public static function getInfo() {
|
|
||||||
return array(
|
|
||||||
'name' => 'Node page cache test',
|
|
||||||
'description' => 'Test cache invalidation of node operations.',
|
|
||||||
'group' => 'Node',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setUp() {
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
$this->container->get('config.factory')->get('system.performance')
|
|
||||||
->set('cache.page.use_internal', 1)
|
|
||||||
->set('cache.page.max_age', 300)
|
|
||||||
->save();
|
|
||||||
|
|
||||||
$this->adminUser = $this->drupalCreateUser(array(
|
|
||||||
'bypass node access',
|
|
||||||
'access content overview',
|
|
||||||
'administer nodes',
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests deleting nodes clears page cache.
|
|
||||||
*/
|
|
||||||
public function testNodeDelete() {
|
|
||||||
$author = $this->drupalCreateUser();
|
|
||||||
$node_id = $this->drupalCreateNode(array('uid' => $author->id()))->id();
|
|
||||||
$node_path = 'node/' . $node_id;
|
|
||||||
|
|
||||||
// Populate page cache.
|
|
||||||
$this->drupalGet($node_path);
|
|
||||||
|
|
||||||
// Verify the presence of the correct cache tags.
|
|
||||||
$cid_parts = array(url($node_path, array('absolute' => TRUE)), 'html');
|
|
||||||
$cid = sha1(implode(':', $cid_parts));
|
|
||||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
|
||||||
$this->assertIdentical($cache_entry->tags, array('content:1', 'node_view:' . $node_id, 'node:' . $node_id, 'user:' . $author->id(), 'filter_format:plain_text'));
|
|
||||||
|
|
||||||
// Login and delete the node.
|
|
||||||
$this->drupalLogin($this->adminUser);
|
|
||||||
$this->drupalGet($node_path . '/delete');
|
|
||||||
$this->drupalPostForm(NULL, array(), t('Delete'));
|
|
||||||
|
|
||||||
// Logout and check the node is not available.
|
|
||||||
$this->drupalLogout();
|
|
||||||
$this->drupalGet($node_path);
|
|
||||||
$this->assertResponse(404);
|
|
||||||
|
|
||||||
// Create two new nodes.
|
|
||||||
$this->drupalCreateNode();
|
|
||||||
$node_path = 'node/' . $this->drupalCreateNode()->id();
|
|
||||||
|
|
||||||
// Populate page cache.
|
|
||||||
$this->drupalGet($node_path);
|
|
||||||
|
|
||||||
// Login and delete the nodes.
|
|
||||||
$this->drupalLogin($this->adminUser);
|
|
||||||
$this->drupalGet('admin/content');
|
|
||||||
$edit = array(
|
|
||||||
'action' => 'node_delete_action',
|
|
||||||
'node_bulk_form[0]' => 1,
|
|
||||||
'node_bulk_form[1]' => 1,
|
|
||||||
);
|
|
||||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
|
||||||
$this->drupalPostForm(NULL, array(), t('Delete'));
|
|
||||||
|
|
||||||
// Logout and check the node is not available.
|
|
||||||
$this->drupalLogout();
|
|
||||||
$this->drupalGet($node_path);
|
|
||||||
$this->assertResponse(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\system\Tests\Cache\PageCacheTagsTestBase.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\system\Tests\Cache;
|
||||||
|
|
||||||
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
use Drupal\Component\Utility\String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides helper methods for page cache tags tests.
|
||||||
|
*/
|
||||||
|
abstract class PageCacheTagsTestBase extends WebTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Enable page caching.
|
||||||
|
$config = \Drupal::config('system.performance');
|
||||||
|
$config->set('cache.page.use_internal', 1);
|
||||||
|
$config->set('cache.page.max_age', 3600);
|
||||||
|
$config->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that when loading a given page, it's a page cache hit or miss.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* The page at this path will be loaded.
|
||||||
|
* @param string $hit_or_miss
|
||||||
|
* 'HIT' if a page cache hit is expected, 'MISS' otherwise.
|
||||||
|
*
|
||||||
|
* @param array|FALSE $tags
|
||||||
|
* When expecting a page cache hit, you may optionally specify an array of
|
||||||
|
* expected cache tags. While FALSE, the cache tags will not be verified.
|
||||||
|
*/
|
||||||
|
protected function verifyPageCache($path, $hit_or_miss, $tags = FALSE) {
|
||||||
|
$this->drupalGet($path);
|
||||||
|
$message = String::format('Page cache @hit_or_miss for %path.', array('@hit_or_miss' => $hit_or_miss, '%path' => $path));
|
||||||
|
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), $hit_or_miss, $message);
|
||||||
|
|
||||||
|
if ($hit_or_miss === 'HIT' && is_array($tags)) {
|
||||||
|
$cid_parts = array(url($path, array('absolute' => TRUE)), 'html');
|
||||||
|
$cid = sha1(implode(':', $cid_parts));
|
||||||
|
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||||
|
$this->assertIdentical($cache_entry->tags, $tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,419 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\system\Tests\Entity\EntityCacheTagsTestBase.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\system\Tests\Entity;
|
||||||
|
|
||||||
|
use Drupal\Component\Utility\String;
|
||||||
|
use Drupal\Core\Cache\Cache;
|
||||||
|
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||||
|
use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides helper methods for Entity cache tags tests.
|
||||||
|
*/
|
||||||
|
abstract class EntityCacheTagsTestBase extends PageCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modules to enable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $modules = array('entity_reference', 'entity_test', 'field_test');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main entity used for testing.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityInterface
|
||||||
|
*/
|
||||||
|
protected $entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity instance referencing the main entity.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityInterface
|
||||||
|
*/
|
||||||
|
protected $referencing_entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity instance not referencing the main entity.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityInterface
|
||||||
|
*/
|
||||||
|
protected $non_referencing_entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Give anonymous users permission to view test entities, so that we can
|
||||||
|
// verify the cache tags of cached versions of test entity pages.
|
||||||
|
$user_role = entity_load('user_role', DRUPAL_ANONYMOUS_RID);
|
||||||
|
$user_role->grantPermission('view test entity');
|
||||||
|
$user_role->save();
|
||||||
|
|
||||||
|
// Create an entity.
|
||||||
|
$this->entity = $this->createEntity();
|
||||||
|
|
||||||
|
// If this is a fieldable entity, then add a configurable field. We will use
|
||||||
|
// this configurable field in later tests to ensure that modifications to
|
||||||
|
// field (instance) configuration invalidate render cache entries.
|
||||||
|
if ($this->entity->getEntityType()->isFieldable()) {
|
||||||
|
// Add field, so we can modify the Field and FieldInstance entities to
|
||||||
|
// verify that changes to those indeed clear cache tags.
|
||||||
|
$field_name = drupal_strtolower($this->randomName());
|
||||||
|
entity_create('field_config', array(
|
||||||
|
'name' => 'configurable_field',
|
||||||
|
'entity_type' => $this->entity->getEntityTypeId(),
|
||||||
|
'type' => 'test_field',
|
||||||
|
'settings' => array(),
|
||||||
|
))->save();
|
||||||
|
entity_create('field_instance_config', array(
|
||||||
|
'entity_type' => $this->entity->getEntityTypeId(),
|
||||||
|
'bundle' => $this->entity->bundle(),
|
||||||
|
'field_name' => 'configurable_field',
|
||||||
|
'label' => 'Configurable field',
|
||||||
|
'settings' => array(),
|
||||||
|
))->save();
|
||||||
|
|
||||||
|
// Reload the entity now that a new field has been added to it.
|
||||||
|
$storage_controller = $this->container
|
||||||
|
->get('entity.manager')
|
||||||
|
->getStorageController($this->entity->getEntityTypeId());
|
||||||
|
$storage_controller->resetCache();
|
||||||
|
$this->entity = $storage_controller->load($this->entity->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a referencing and a non-referencing entity.
|
||||||
|
list(
|
||||||
|
$this->referencing_entity,
|
||||||
|
$this->non_referencing_entity,
|
||||||
|
) = $this->createReferenceTestEntities($this->entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates standardized entity cache tags test info.
|
||||||
|
*
|
||||||
|
* @param string $entity_type_label
|
||||||
|
* The label of the entity type whose cache tags to test.
|
||||||
|
* @param string $group
|
||||||
|
* The test group.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @see \Drupal\simpletest\TestBase::getInfo()
|
||||||
|
*/
|
||||||
|
protected static function generateStandardizedInfo($entity_type_label, $group) {
|
||||||
|
return array(
|
||||||
|
'name' => "$entity_type_label entity cache tags",
|
||||||
|
'description' => "Test the $entity_type_label entity's cache tags.",
|
||||||
|
'group' => $group,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the entity to be tested.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Entity\EntityInterface
|
||||||
|
* The entity to be tested.
|
||||||
|
*/
|
||||||
|
abstract protected function createEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a referencing and a non-referencing entity for testing purposes.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Entity\EntityInterface $referenced_entity
|
||||||
|
* The entity that the referencing entity should reference.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Entity\EntityInterface[]
|
||||||
|
* An array containing a referencing entity and a non-referencing entity.
|
||||||
|
*/
|
||||||
|
protected function createReferenceTestEntities($referenced_entity) {
|
||||||
|
// All referencing entities should be of the type 'entity_test'.
|
||||||
|
$entity_type = 'entity_test';
|
||||||
|
|
||||||
|
// Create a "foo" bundle for the given entity type.
|
||||||
|
$bundle = 'foo';
|
||||||
|
entity_test_create_bundle($bundle, NULL, $entity_type);
|
||||||
|
|
||||||
|
// Add a field of the given type to the given entity type's "foo" bundle.
|
||||||
|
$field_name = $referenced_entity->getEntityTypeId() . '_reference';
|
||||||
|
entity_create('field_config', array(
|
||||||
|
'name' => $field_name,
|
||||||
|
'entity_type' => $entity_type,
|
||||||
|
'type' => 'entity_reference',
|
||||||
|
'cardinality' => FieldDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||||
|
'settings' => array(
|
||||||
|
'target_type' => $referenced_entity->getEntityTypeId(),
|
||||||
|
),
|
||||||
|
))->save();
|
||||||
|
entity_create('field_instance_config', array(
|
||||||
|
'field_name' => $field_name,
|
||||||
|
'entity_type' => $entity_type,
|
||||||
|
'bundle' => $bundle,
|
||||||
|
'settings' => array(
|
||||||
|
'handler' => 'default',
|
||||||
|
'handler_settings' => array(
|
||||||
|
'target_bundles' => array(
|
||||||
|
$referenced_entity->bundle() => $referenced_entity->bundle(),
|
||||||
|
),
|
||||||
|
'sort' => array('field' => '_none'),
|
||||||
|
'auto_create' => FALSE,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))->save();
|
||||||
|
entity_get_display($entity_type, $bundle, 'full')
|
||||||
|
->setComponent($field_name, array('type' => 'entity_reference_label'))
|
||||||
|
->save();
|
||||||
|
|
||||||
|
// Create an entity that does reference the entity being tested.
|
||||||
|
$label_key = \Drupal::entityManager()->getDefinition($entity_type)->getKey('label');
|
||||||
|
$referencing_entity = entity_create($entity_type, array(
|
||||||
|
$label_key => 'Referencing ' . $entity_type,
|
||||||
|
'status' => 1,
|
||||||
|
'type' => $bundle,
|
||||||
|
$field_name => array('target_id' => $referenced_entity->id()),
|
||||||
|
));
|
||||||
|
$referencing_entity->save();
|
||||||
|
|
||||||
|
// Create an entity that does not reference the entity being tested.
|
||||||
|
$non_referencing_entity = entity_create($entity_type, array(
|
||||||
|
$label_key => 'Non-referencing ' . $entity_type,
|
||||||
|
'status' => 1,
|
||||||
|
'type' => $bundle,
|
||||||
|
));
|
||||||
|
$non_referencing_entity->save();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$referencing_entity,
|
||||||
|
$non_referencing_entity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests cache tags presence and invalidation of the entity when referenced.
|
||||||
|
*
|
||||||
|
* Tests the following cache tags:
|
||||||
|
* - "<entity type>_view:1"
|
||||||
|
* - "<entity type>:<entity ID>"
|
||||||
|
* - "<referencing entity type>_view:1"
|
||||||
|
* * - "<referencing entity type>:<referencing entity ID>"
|
||||||
|
*/
|
||||||
|
public function testReferencedEntity() {
|
||||||
|
$entity_type = $this->entity->getEntityTypeId();
|
||||||
|
$referencing_entity_path = $this->referencing_entity->getSystemPath();
|
||||||
|
$non_referencing_entity_path = $this->non_referencing_entity->getSystemPath();
|
||||||
|
$listing_path = 'entity_test/list/' . $entity_type . '_reference/' . $entity_type . '/' . $this->entity->id();
|
||||||
|
|
||||||
|
// Generate the standardized entity cache tags.
|
||||||
|
$cache_tag = $entity_type . ':' . $this->entity->id();
|
||||||
|
$view_cache_tag = $entity_type . '_view:1';
|
||||||
|
|
||||||
|
// Generate the cache tags for the (non) referencing entities.
|
||||||
|
$referencing_entity_cache_tags = array(
|
||||||
|
'entity_test_view:1',
|
||||||
|
'entity_test:' . $this->referencing_entity->id(),
|
||||||
|
// Includes the main entity's cache tags, since this entity references it.
|
||||||
|
$cache_tag,
|
||||||
|
$view_cache_tag
|
||||||
|
);
|
||||||
|
$non_referencing_entity_cache_tags = array(
|
||||||
|
'entity_test_view:1',
|
||||||
|
'entity_test:' . $this->non_referencing_entity->id(),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Prime the page cache for the referencing entity.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||||
|
$tags = array_merge(array('content:1'), $referencing_entity_cache_tags);
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT', $tags);
|
||||||
|
|
||||||
|
// Also verify the existence of an entity render cache entry.
|
||||||
|
$cid = 'entity_view:entity_test:' . $this->referencing_entity->id() . ':full:stark:r.anonymous';
|
||||||
|
$cache_entry = \Drupal::cache()->get($cid);
|
||||||
|
$this->assertIdentical($cache_entry->tags, $referencing_entity_cache_tags);
|
||||||
|
|
||||||
|
|
||||||
|
// Prime the page cache for the non-referencing entity.
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||||
|
$tags = array_merge(array('content:1'), $non_referencing_entity_cache_tags);
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT', $tags);
|
||||||
|
|
||||||
|
// Also verify the existence of an entity render cache entry.
|
||||||
|
$cid = 'entity_view:entity_test:' . $this->non_referencing_entity->id() . ':full:stark:r.anonymous';
|
||||||
|
$cache_entry = \Drupal::cache()->get($cid);
|
||||||
|
$this->assertIdentical($cache_entry->tags, $non_referencing_entity_cache_tags);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Prime the page cache for the listing of referencing entities.
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||||
|
$tags = array_merge(array('content:1'), $referencing_entity_cache_tags);
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT', $tags);
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the referenced entity, there is a cache miss
|
||||||
|
// for both the referencing entity, and the listing of referencing entities,
|
||||||
|
// but not for the non-referencing entity.
|
||||||
|
$this->pass("Test modification of referenced entity.", 'Debug');
|
||||||
|
$this->entity->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the referencing entity, there is a cache miss
|
||||||
|
// for both the referencing entity, and the listing of referencing entities,
|
||||||
|
// but not for the non-referencing entity.
|
||||||
|
$this->pass("Test modification of referencing entity.", 'Debug');
|
||||||
|
$this->referencing_entity->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the non-referencing entity, there is a cache
|
||||||
|
// miss for only the non-referencing entity, not for the referencing entity,
|
||||||
|
// nor for the listing of referencing entities.
|
||||||
|
$this->pass("Test modification of non-referencing entity.", 'Debug');
|
||||||
|
$this->non_referencing_entity->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the entity's "full" display, there is a cache
|
||||||
|
// miss for both the referencing entity, and the listing of referencing
|
||||||
|
// entities, but not for the non-referencing entity.
|
||||||
|
$this->pass("Test modification of referenced entity's 'full' display.", 'Debug');
|
||||||
|
$entity_display = entity_get_display($entity_type, $this->entity->bundle(), 'full');
|
||||||
|
$entity_display->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
$bundle_entity_type = $this->entity->getEntityType()->getBundleEntityType();
|
||||||
|
if ($bundle_entity_type !== 'bundle') {
|
||||||
|
// Verify that after modifying the corresponding bundle entity, there is a
|
||||||
|
// cache miss for both the referencing entity, and the listing of
|
||||||
|
// referencing entities, but not for the non-referencing entity.
|
||||||
|
$this->pass("Test modification of referenced entity's bundle entity.", 'Debug');
|
||||||
|
$bundle_entity = entity_load($bundle_entity_type, $this->entity->bundle());
|
||||||
|
$bundle_entity->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($this->entity->getEntityType()->isFieldable()) {
|
||||||
|
// Verify that after modifying a configurable field on the entity, there
|
||||||
|
// is a cache miss.
|
||||||
|
$this->pass("Test modification of referenced entity's configurable field.", 'Debug');
|
||||||
|
$field_name = $this->entity->getEntityTypeId() . '.configurable_field';
|
||||||
|
$field = entity_load('field_config', $field_name);
|
||||||
|
$field->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying a configurable field instance on the
|
||||||
|
// entity, there is a cache miss.
|
||||||
|
$this->pass("Test modification of referenced entity's configurable field instance.", 'Debug');
|
||||||
|
$field_instance_name = $this->entity->getEntityTypeId() . '.' . $this->entity->bundle() . '.configurable_field';
|
||||||
|
$field_instance = entity_load('field_instance_config', $field_instance_name);
|
||||||
|
$field_instance->save();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after invalidating the entity's cache tag directly, there is
|
||||||
|
// a cache miss for both the referencing entity, and the listing of
|
||||||
|
// referencing entities, but not for the non-referencing entity.
|
||||||
|
$this->pass("Test invalidation of referenced entity's cache tag.", 'Debug');
|
||||||
|
Cache::invalidateTags(array($entity_type => array($this->entity->id())));
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after invalidating the generic entity type's view cache tag
|
||||||
|
// directly, there is a cache miss for both the referencing entity, and the
|
||||||
|
// listing of referencing entities, but not for the non-referencing entity.
|
||||||
|
$this->pass("Test invalidation of referenced entity's 'view' cache tag.", 'Debug');
|
||||||
|
Cache::invalidateTags(array($entity_type . '_view' => TRUE));
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT');
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after deleting the entity, there is a cache miss for both the
|
||||||
|
// referencing entity, and the listing of referencing entities, but not for
|
||||||
|
// the non-referencing entity.
|
||||||
|
$this->pass('Test deletion of referenced entity.', 'Debug');
|
||||||
|
$this->entity->delete();
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'MISS');
|
||||||
|
$this->verifyPageCache($listing_path, 'MISS');
|
||||||
|
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Verify cache hits.
|
||||||
|
$tags = array(
|
||||||
|
'content:1',
|
||||||
|
'entity_test_view:1',
|
||||||
|
'entity_test:' . $this->referencing_entity->id(),
|
||||||
|
);
|
||||||
|
$this->verifyPageCache($referencing_entity_path, 'HIT', $tags);
|
||||||
|
$this->verifyPageCache($listing_path, 'HIT', array('content:1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ class EntityViewBuilderTest extends EntityUnitTestBase {
|
||||||
// Test that new entities (before they are saved for the first time) do not
|
// Test that new entities (before they are saved for the first time) do not
|
||||||
// generate a cache entry.
|
// generate a cache entry.
|
||||||
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full');
|
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full');
|
||||||
$this->assertFalse(isset($build['#cache']), 'The render array element of new (unsaved) entities is not cached.');
|
$this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags'), 'The render array element of new (unsaved) entities is not cached, but does have cache tags set.');
|
||||||
|
|
||||||
// Get a fully built entity view render array.
|
// Get a fully built entity view render array.
|
||||||
$entity_test->save();
|
$entity_test->save();
|
||||||
|
@ -144,17 +144,17 @@ class EntityViewBuilderTest extends EntityUnitTestBase {
|
||||||
// Test a view mode in default conditions: render caching is enabled for
|
// Test a view mode in default conditions: render caching is enabled for
|
||||||
// the entity type and the view mode.
|
// the entity type and the view mode.
|
||||||
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full');
|
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full');
|
||||||
$this->assertTrue(isset($build['#cache']), 'A view mode with render cache enabled has the correct output.');
|
$this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags', 'keys', 'granularity', 'bin') , 'A view mode with render cache enabled has the correct output (cache tags, keys, granularity and bin).');
|
||||||
|
|
||||||
// Test that a view mode can opt out of render caching.
|
// Test that a view mode can opt out of render caching.
|
||||||
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'test');
|
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'test');
|
||||||
$this->assertFalse(isset($build['#cache']), 'A view mode with render cache disabled has the correct output.');
|
$this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags'), 'A view mode with render cache disabled has the correct output (only cache tags).');
|
||||||
|
|
||||||
// Test that an entity type can opt out of render caching completely.
|
// Test that an entity type can opt out of render caching completely.
|
||||||
$entity_test_no_cache = $this->createTestEntity('entity_test_label');
|
$entity_test_no_cache = $this->createTestEntity('entity_test_label');
|
||||||
$entity_test_no_cache->save();
|
$entity_test_no_cache->save();
|
||||||
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test_label')->view($entity_test_no_cache, 'full');
|
$build = $this->container->get('entity.manager')->getViewBuilder('entity_test_label')->view($entity_test_no_cache, 'full');
|
||||||
$this->assertFalse(isset($build['#cache']), 'An entity type can opt out of render caching regardless of view mode configuration.');
|
$this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags'), 'An entity type can opt out of render caching regardless of view mode configuration, but always has cache tags set.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\system\Tests\Entity;
|
||||||
|
|
||||||
|
use Drupal\Core\Cache\Cache;
|
||||||
|
use Drupal\Core\Entity\EntityInterface;
|
||||||
|
use Drupal\system\Tests\Entity\EntityCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides helper methods for Entity cache tags tests; for entities with URIs.
|
||||||
|
*/
|
||||||
|
abstract class EntityWithUriCacheTagsTestBase extends EntityCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the additional (non-standard) cache tags for the tested entity.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||||
|
* The entity to be tested, as created by createEntity().
|
||||||
|
* @return array
|
||||||
|
* An array of the additional cache tags.
|
||||||
|
*
|
||||||
|
* @see \Drupal\system\Tests\Entity\EntityCacheTagsTestBase::createEntity()
|
||||||
|
*/
|
||||||
|
protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests cache tags presence and invalidation of the entity at its URI.
|
||||||
|
*
|
||||||
|
* Tests the following cache tags:
|
||||||
|
* - "<entity type>_view:1"
|
||||||
|
* - "<entity_type>:<entity ID>"
|
||||||
|
*/
|
||||||
|
public function testEntityUri() {
|
||||||
|
$entity_path = $this->entity->getSystemPath();
|
||||||
|
$entity_type = $this->entity->getEntityTypeId();
|
||||||
|
|
||||||
|
// Generate the standardized entity cache tags.
|
||||||
|
$cache_tag = $entity_type . ':' . $this->entity->id();
|
||||||
|
$view_cache_tag = $entity_type . '_view:1';
|
||||||
|
|
||||||
|
|
||||||
|
// Prime the page cache.
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||||
|
$tags = array('content:1', $view_cache_tag, $cache_tag);
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
|
||||||
|
// Also verify the existence of an entity render cache entry, if this entity
|
||||||
|
// type supports render caching.
|
||||||
|
if (\Drupal::entityManager()->getDefinition($entity_type)->isRenderCacheable()) {
|
||||||
|
$cid = 'entity_view:' . $entity_type . ':' . $this->entity->id() . ':full:stark:r.anonymous';
|
||||||
|
$cache_entry = \Drupal::cache()->get($cid);
|
||||||
|
$expected_cache_tags = array_merge(array($view_cache_tag, $cache_tag), $this->getAdditionalCacheTagsForEntity($this->entity));
|
||||||
|
$this->assertIdentical($cache_entry->tags, $expected_cache_tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that after modifying the entity, there is a cache miss.
|
||||||
|
$this->pass("Test modification of entity.", 'Debug');
|
||||||
|
$this->entity->save();
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying the entity's "full" display, there is a cache
|
||||||
|
// miss.
|
||||||
|
$this->pass("Test modification of entity's 'full' display.", 'Debug');
|
||||||
|
$entity_display = entity_get_display($entity_type, $this->entity->bundle(), 'full');
|
||||||
|
$entity_display->save();
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
$bundle_entity_type = $this->entity->getEntityType()->getBundleEntityType();
|
||||||
|
if ($bundle_entity_type !== 'bundle') {
|
||||||
|
// Verify that after modifying the corresponding bundle entity, there is a
|
||||||
|
// cache miss.
|
||||||
|
$this->pass("Test modification of entity's bundle entity.", 'Debug');
|
||||||
|
$bundle_entity = entity_load($bundle_entity_type, $this->entity->bundle());
|
||||||
|
$bundle_entity->save();
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($this->entity->getEntityType()->isFieldable()) {
|
||||||
|
// Verify that after modifying a configurable field on the entity, there
|
||||||
|
// is a cache miss.
|
||||||
|
$this->pass("Test modification of entity's configurable field.", 'Debug');
|
||||||
|
$field_name = $this->entity->getEntityTypeId() . '.configurable_field';
|
||||||
|
$field = entity_load('field_config', $field_name);
|
||||||
|
$field->save();
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after modifying a configurable field instance on the
|
||||||
|
// entity, there is a cache miss.
|
||||||
|
$this->pass("Test modification of entity's configurable field instance.", 'Debug');
|
||||||
|
$field_instance_name = $this->entity->getEntityTypeId() . '.' . $this->entity->bundle() . '.configurable_field';
|
||||||
|
$field_instance = entity_load('field_instance_config', $field_instance_name);
|
||||||
|
$field_instance->save();
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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(array($entity_type => array($this->entity->id())));
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after invalidating the generic entity type's view cache tag
|
||||||
|
// directly, there is a cache miss.
|
||||||
|
$this->pass("Test invalidation of entity's 'view' cache tag.", 'Debug');
|
||||||
|
Cache::invalidateTags(array($entity_type . '_view' => TRUE));
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
|
||||||
|
// Verify a cache hit.
|
||||||
|
$this->verifyPageCache($entity_path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
|
// Verify that after deleting the entity, there is a cache miss.
|
||||||
|
$this->pass('Test deletion of entity.', 'Debug');
|
||||||
|
$this->entity->delete();
|
||||||
|
$this->verifyPageCache($entity_path, 'MISS');
|
||||||
|
$this->assertResponse(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,5 +23,13 @@ entity_test.render_no_view_mode:
|
||||||
requirements:
|
requirements:
|
||||||
_access: 'TRUE'
|
_access: 'TRUE'
|
||||||
|
|
||||||
|
entity_test.list_referencing_entities:
|
||||||
|
path: '/entity_test/list/{entity_reference_field_name}/{referenced_entity_type}/{referenced_entity_id}'
|
||||||
|
defaults:
|
||||||
|
_content: '\Drupal\entity_test\Controller\EntityTestController::listReferencingEntities'
|
||||||
|
_title: 'List entity_test entities referencing the given entity'
|
||||||
|
requirements:
|
||||||
|
_access: 'TRUE'
|
||||||
|
|
||||||
route_callbacks:
|
route_callbacks:
|
||||||
- '\Drupal\entity_test\Routing\EntityTestRoutes::routes'
|
- '\Drupal\entity_test\Routing\EntityTestRoutes::routes'
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
namespace Drupal\entity_test\Controller;
|
namespace Drupal\entity_test\Controller;
|
||||||
|
|
||||||
use Drupal\Core\Controller\ControllerBase;
|
use Drupal\Core\Controller\ControllerBase;
|
||||||
|
use Drupal\Core\Entity\Query\QueryFactory;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +17,32 @@ use Symfony\Component\HttpFoundation\Request;
|
||||||
*/
|
*/
|
||||||
class EntityTestController extends ControllerBase {
|
class EntityTestController extends ControllerBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity query factory.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\Query\QueryFactory
|
||||||
|
*/
|
||||||
|
protected $entityQueryFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new EntityTestController.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Entity\Query\QueryFactory
|
||||||
|
* The entity query factory.
|
||||||
|
*/
|
||||||
|
public function __construct(QueryFactory $entity_query_factory) {
|
||||||
|
$this->entityQueryFactory = $entity_query_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container) {
|
||||||
|
return new static(
|
||||||
|
$container->get('entity.query')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the 'Add new entity_test' form.
|
* Displays the 'Add new entity_test' form.
|
||||||
*
|
*
|
||||||
|
@ -60,4 +88,37 @@ class EntityTestController extends ControllerBase {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List entity_test entities referencing the given entity.
|
||||||
|
*
|
||||||
|
* @param string $entity_reference_field_name
|
||||||
|
* The name of the entity_reference field to use in the query.
|
||||||
|
* @param string $referenced_entity_type
|
||||||
|
* The type of the entity being referenced.
|
||||||
|
* @param int $referenced_entity_id
|
||||||
|
* The ID of the entity being referenced.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* A renderable array.
|
||||||
|
*/
|
||||||
|
public function listReferencingEntities($entity_reference_field_name, $referenced_entity_type, $referenced_entity_id) {
|
||||||
|
// Early return if the referenced entity does not exist (or is deleted).
|
||||||
|
$referenced_entity = $this->entityManager()
|
||||||
|
->getStorageController($referenced_entity_type)
|
||||||
|
->load($referenced_entity_id);
|
||||||
|
if ($referenced_entity === NULL) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->entityQueryFactory
|
||||||
|
->get('entity_test')
|
||||||
|
->condition($entity_reference_field_name . '.target_id', $referenced_entity_id);
|
||||||
|
$entities = $this->entityManager()
|
||||||
|
->getStorageController('entity_test')
|
||||||
|
->loadMultiple($query->execute());
|
||||||
|
return $this->entityManager()
|
||||||
|
->getViewBuilder('entity_test')
|
||||||
|
->viewMultiple($entities, 'full');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\taxonomy\Tests\TermCacheTagsTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\taxonomy\Tests;
|
||||||
|
|
||||||
|
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the Taxonomy term entity's cache tags.
|
||||||
|
*/
|
||||||
|
class TermCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = array('taxonomy');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return parent::generateStandardizedInfo('Taxonomy term', 'Taxonomy');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createEntity() {
|
||||||
|
// Create a "Camelids" vocabulary.
|
||||||
|
$vocabulary = entity_create('taxonomy_vocabulary', array(
|
||||||
|
'name' => 'Camelids',
|
||||||
|
'vid' => 'camelids',
|
||||||
|
));
|
||||||
|
$vocabulary->save();
|
||||||
|
|
||||||
|
// Create a "Llama" taxonomy term.
|
||||||
|
$term = entity_create('taxonomy_term', array(
|
||||||
|
'name' => 'Llama',
|
||||||
|
'vid' => $vocabulary->id(),
|
||||||
|
));
|
||||||
|
$term->save();
|
||||||
|
|
||||||
|
return $term;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,12 +16,11 @@ use Drupal\Core\Config\Entity\ConfigStorageController;
|
||||||
class VocabularyStorageController extends ConfigStorageController implements VocabularyStorageControllerInterface {
|
class VocabularyStorageController extends ConfigStorageController implements VocabularyStorageControllerInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides Drupal\Core\Config\Entity\ConfigStorageController::resetCache().
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function resetCache(array $ids = NULL) {
|
public function resetCache(array $ids = NULL) {
|
||||||
drupal_static_reset('taxonomy_vocabulary_get_names');
|
drupal_static_reset('taxonomy_vocabulary_get_names');
|
||||||
parent::resetCache($ids);
|
parent::resetCache($ids);
|
||||||
Cache::invalidateTags(array('content' => TRUE));
|
|
||||||
entity_info_cache_clear();
|
entity_info_cache_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\user\Tests\UserCacheTagsTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\user\Tests;
|
||||||
|
|
||||||
|
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the User entity's cache tags.
|
||||||
|
*/
|
||||||
|
class UserCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = array('user');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return parent::generateStandardizedInfo('User', 'User');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Give anonymous users permission to view user profiles, so that we can
|
||||||
|
// verify the cache tags of cached versions of user profile pages.
|
||||||
|
$user_role = entity_load('user_role', DRUPAL_ANONYMOUS_RID);
|
||||||
|
$user_role->grantPermission('access user profiles');
|
||||||
|
$user_role->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createEntity() {
|
||||||
|
// Create a "Llama" user.
|
||||||
|
$user = entity_create('user', array(
|
||||||
|
'name' => 'Llama',
|
||||||
|
));
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue