diff --git a/core/includes/common.inc b/core/includes/common.inc
index 48db270..d1e9b97 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4103,7 +4103,7 @@ function drupal_render_cache_set(&$markup, $elements) {
}
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CacheBackendInterface::CACHE_PERMANENT;
- $tags = isset($elements['#cache']['tags']) ? $elements['#cache']['tags'] : array();
+ $tags = drupal_render_collect_cache_tags($elements, TRUE);
cache($bin)->set($cid, $data, $expire, $tags);
}
@@ -4151,6 +4151,57 @@ function drupal_render_collect_attached($elements, $return = FALSE) {
}
/**
+ * Collects cache tags for an element and its children into a single array.
+ *
+ * When caching elements, it is necessary to collect all cache tags into a
+ * single array, from both the element itself and all child elements. This
+ * allows items to be invalidated based on all tags attached to the content
+ * they're constituted from.
+ *
+ * @param array $elements
+ * The element to collect cache tags from.
+ * @param bool $return
+ * Whether to return the attached elements and reset the internal static.
+ *
+ * @return array
+ * The cache tags array for this element and its descendants.
+ */
+function drupal_render_collect_cache_tags($elements, $return = FALSE) {
+ $tags = &drupal_static(__FUNCTION__, array());
+
+ // Collect all cache tags for this element.
+ if (isset($elements['#cache']['tags'])) {
+ foreach ($elements['#cache']['tags'] as $namespace => $values) {
+ if (is_array($values)) {
+ foreach ($values as $value) {
+ if (!isset($tags[$namespace][$value])) {
+ $tags[$namespace][$value] = $value;
+ }
+ }
+ }
+ else {
+ if (!isset($tags[$namespace])) {
+ $tags[$namespace] = $values;
+ }
+ }
+ }
+ }
+ if ($children = element_children($elements)) {
+ foreach ($children as $child) {
+ drupal_render_collect_cache_tags($elements[$child]);
+ }
+ }
+
+ // If this was the first call to the function, return all attached elements
+ // and reset the static cache.
+ if ($return) {
+ $return = $tags;
+ $tags = array();
+ return $return;
+ }
+}
+
+/**
* Prepares an element for caching based on a query.
*
* This smart caching strategy saves Drupal from querying and rendering to HTML
diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 7822d7a..8697c0e 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -48,6 +48,18 @@ function entity_info_cache_clear() {
}
/**
+ * Clears the entity render cache for all entity types.
+ */
+function entity_render_cache_clear() {
+ $entity_manager = Drupal::entityManager();
+ foreach ($entity_manager->getDefinitions() as $entity_type => $info) {
+ if ($entity_manager->hasController($entity_type, 'render')) {
+ $entity_manager->getRenderController($entity_type)->resetCache();
+ }
+ }
+}
+
+/**
* Returns the entity bundle info.
*
* @param string|null $entity_type
@@ -622,14 +634,19 @@ function entity_render_controller($entity_type) {
* @param string $langcode
* (optional) For which language the entity should be rendered, defaults to
* the current content language.
+ * @param bool $reset
+ * (optional) Whether to reset the render cache for the requested entity.
+ * Defaults to FALSE.
*
* @return array
* A render array for the entity.
*/
-function entity_view(EntityInterface $entity, $view_mode, $langcode = NULL) {
- return Drupal::entityManager()
- ->getRenderController($entity->entityType())
- ->view($entity, $view_mode, $langcode);
+function entity_view(EntityInterface $entity, $view_mode, $langcode = NULL, $reset = FALSE) {
+ $render_controller = Drupal::entityManager()->getRenderController($entity->entityType());
+ if ($reset) {
+ $render_controller->resetCache(array($entity->id()));
+ }
+ return $render_controller->view($entity, $view_mode, $langcode);
}
/**
@@ -642,15 +659,20 @@ function entity_view(EntityInterface $entity, $view_mode, $langcode = NULL) {
* @param string $langcode
* (optional) For which language the entity should be rendered, defaults to
* the current content language.
+ * @param bool $reset
+ * (optional) Whether to reset the render cache for the requested entities.
+ * Defaults to FALSE.
*
* @return array
* A render array for the entities, indexed by the same keys as the
* entities array passed in $entities.
*/
-function entity_view_multiple(array $entities, $view_mode, $langcode = NULL) {
- return Drupal::entityManager()
- ->getRenderController(reset($entities)->entityType())
- ->viewMultiple($entities, $view_mode, $langcode);
+function entity_view_multiple(array $entities, $view_mode, $langcode = NULL, $reset = FALSE) {
+ $render_controller = Drupal::entityManager()->getRenderController(reset($entities)->entityType());
+ if ($reset) {
+ $render_controller->resetCache(array_keys($entities));
+ }
+ return $render_controller->viewMultiple($entities, $view_mode, $langcode);
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php
index b8e4061..79e5c52 100644
--- a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php
@@ -138,6 +138,14 @@ class EntityType extends Plugin {
public $static_cache = TRUE;
/**
+ * Boolean indicating whether the rendered output of entities should be
+ * cached.
+ *
+ * @var bool (optional)
+ */
+ public $render_cache = TRUE;
+
+ /**
* Boolean indicating whether entities of this type have multilingual support.
*
* At an entity level, this indicates language support and at a bundle level
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index ec05c1a..908b36c 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\Component\Uuid\Uuid;
+use Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem;
use Drupal\Core\Language\Language;
use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\Core\TypedData\TypedDataInterface;
@@ -354,7 +355,9 @@ public function getTranslationLanguages($include_default = TRUE) {
* Implements \Drupal\Core\Entity\EntityInterface::save().
*/
public function save() {
- return \Drupal::entityManager()->getStorageController($this->entityType)->save($this);
+ $return = \Drupal::entityManager()->getStorageController($this->entityType)->save($this);
+ $this->changed();
+ return $return;
}
/**
@@ -363,6 +366,7 @@ public function save() {
public function delete() {
if (!$this->isNew()) {
\Drupal::entityManager()->getStorageController($this->entityType)->delete(array($this->id() => $this));
+ $this->changed();
}
}
@@ -642,4 +646,45 @@ public function initTranslation($langcode) {
// http://drupal.org/node/2004244
}
+ /**
+ * {@inheritdoc}
+ */
+ public function relatedEntities() {
+ $relationships = array();
+
+ // @todo Remove when all entities are converted to EntityNG.
+ if (!$this->getPropertyDefinitions()) {
+ return $relationships;
+ }
+
+ // Gather a list of related entities.
+ foreach ($this->getProperties() as $name => $definition) {
+ $field_item = $this->get($name)->offsetGet(0);
+ if ($field_item instanceof EntityReferenceItem && $entity = $field_item->entity) {
+ $relationships[] = $entity;
+ }
+ }
+
+ return $relationships;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function changed() {
+ $related_entity_ids = array(
+ $this->entityType() => array($this->id() => TRUE),
+ );
+
+ foreach ($this->relatedEntities() as $related_entity) {
+ $related_entity_ids[$related_entity->entityType()][$related_entity->id()] = TRUE;
+ }
+
+ foreach ($related_entity_ids as $entity_type => $entity_ids) {
+ if (\Drupal::entityManager()->hasController($entity_type, 'render')) {
+ \Drupal::entityManager()->getRenderController($entity_type)->resetCache(array_keys($entity_ids));
+ }
+ }
+ }
+
}
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index a3ffcb9..55ee3b4 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -626,4 +626,20 @@ public function initTranslation($langcode) {
$this->decorated->initTranslation($langcode);
}
+ /**
+ * {@inheritdoc}
+ *
+ * @return array
+ */
+ public function relatedEntities() {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function changed(array $tags = array()) {
+ $this->decorated->changed($tags);
+ }
+
}
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index e965b8e..a1a6642 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -326,4 +326,16 @@ public function isTranslatable();
*/
public function initTranslation($langcode);
+ /**
+ * @todo
+ *
+ * @return array
+ */
+ public function relatedEntities();
+
+ /**
+ * @todo
+ */
+ public function changed();
+
}
diff --git a/core/lib/Drupal/Core/Entity/EntityRenderController.php b/core/lib/Drupal/Core/Entity/EntityRenderController.php
index cd92f52..9d82d09 100644
--- a/core/lib/Drupal/Core/Entity/EntityRenderController.php
+++ b/core/lib/Drupal/Core/Entity/EntityRenderController.php
@@ -6,9 +6,10 @@
*/
namespace Drupal\Core\Entity;
-use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
+use Drupal\Core\Entity\Plugin\DataType\EntityReferenceItem;
use Drupal\Core\Language\Language;
+use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
/**
* Base class for entity view controllers.
@@ -22,8 +23,37 @@ class EntityRenderController implements EntityRenderControllerInterface {
*/
protected $entityType;
+ /**
+ * The entity info array.
+ *
+ * @var array
+ *
+ * @see entity_get_info()
+ */
+ protected $entityInfo;
+
+ /**
+ * An array of view mode info for the type of entities for which this
+ * controller is instantiated.
+ *
+ * @var array
+ */
+ protected $viewModesInfo;
+
+ /**
+ * The cache bin used to store the render cache.
+ *
+ * @todo Defaults to 'cache' for now, until http://drupal.org/node/1194136 is
+ * fixed.
+ *
+ * @var string
+ */
+ protected $cacheBin = 'cache';
+
public function __construct($entity_type) {
$this->entityType = $entity_type;
+ $this->entityInfo = entity_get_info($entity_type);
+ $this->viewModesInfo = entity_get_view_modes($entity_type);
}
/**
@@ -62,6 +92,24 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco
'#view_mode' => $view_mode,
'#langcode' => $langcode,
);
+
+ // Cache the rendered output if permitted by the view mode settings.
+ // @todo Fix the tests that require non-existent view modes and remove the
+ // isset() checks below.
+ $view_mode_is_cacheable = !isset($this->viewModesInfo[$view_mode]) || (isset($this->viewModesInfo[$view_mode]) && $this->viewModesInfo[$view_mode]['cache']);
+ if (!isset($entity->in_preview) && $this->entityInfo['render_cache'] && $view_mode_is_cacheable) {
+ $request = \Drupal::request();
+ $return['#cache'] = array(
+ 'keys' => array('entity_view', $this->entityType ,$entity->id(), $view_mode, $request->getQueryString()),
+ 'granularity' => DRUPAL_CACHE_PER_ROLE,
+ 'bin' => $this->cacheBin,
+ 'tags' => array(
+ $this->entityType . '_view' => TRUE,
+ $this->entityType => array($entity->id()),
+ ),
+ );
+ }
+
return $return;
}
@@ -164,4 +212,20 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
return $build;
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function resetCache(array $ids = NULL) {
+ if (isset($ids)) {
+ $tags = array();
+ foreach ($ids as $entity_id) {
+ $tags[$this->entityType][$entity_id] = $entity_id;
+ }
+ \Drupal::cache($this->cacheBin)->deleteTags($tags);
+ }
+ else {
+ \Drupal::cache($this->cacheBin)->deleteTags(array($this->entityType . '_view' => TRUE));
+ }
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/EntityRenderControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityRenderControllerInterface.php
index 03ba014..a112fc2 100644
--- a/core/lib/Drupal/Core/Entity/EntityRenderControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityRenderControllerInterface.php
@@ -75,4 +75,14 @@ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = N
* be available for loading.
*/
public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL);
+
+ /**
+ * Resets the entity render cache.
+ *
+ * @param array|null $ids
+ * (optional) If specified, the cache is reset for the given entity IDs
+ * only.
+ */
+ public function resetCache(array $ids = NULL);
+
}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Tests/Views/IntegrationTest.php b/core/modules/aggregator/lib/Drupal/aggregator/Tests/Views/IntegrationTest.php
index da85242..d31c46e 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Tests/Views/IntegrationTest.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Tests/Views/IntegrationTest.php
@@ -20,7 +20,7 @@ class IntegrationTest extends ViewUnitTestBase {
*
* @var array
*/
- public static $modules = array('aggregator', 'aggregator_test_views', 'system', 'field');
+ public static $modules = array('aggregator', 'aggregator_test_views', 'system', 'entity', 'field');
/**
* Views used by this test.
diff --git a/core/modules/block/custom_block/config/entity.view_mode.custom_block.full.yml b/core/modules/block/custom_block/config/entity.view_mode.custom_block.full.yml
index ebacec5..6c2a3d1 100644
--- a/core/modules/block/custom_block/config/entity.view_mode.custom_block.full.yml
+++ b/core/modules/block/custom_block/config/entity.view_mode.custom_block.full.yml
@@ -1,4 +1,5 @@
id: custom_block.full
label: Full
status: '0'
+cache: '1'
targetEntityType: custom_block
diff --git a/core/modules/block/lib/Drupal/block/BlockRenderController.php b/core/modules/block/lib/Drupal/block/BlockRenderController.php
index 57a5d62..19418ae 100644
--- a/core/modules/block/lib/Drupal/block/BlockRenderController.php
+++ b/core/modules/block/lib/Drupal/block/BlockRenderController.php
@@ -62,4 +62,10 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
return $build;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function resetCache(array $ids = NULL) {
+ // @todo Move block render caching logic to this controller?
+ }
}
diff --git a/core/modules/book/config/entity.view_mode.node.print.yml b/core/modules/book/config/entity.view_mode.node.print.yml
index fe45f50..6f7333f 100644
--- a/core/modules/book/config/entity.view_mode.node.print.yml
+++ b/core/modules/book/config/entity.view_mode.node.print.yml
@@ -1,4 +1,5 @@
id: node.print
label: Print
status: '0'
+cache: '1'
targetEntityType: node
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index 221fbfc..d88b63a 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -81,6 +81,7 @@ function comment_reply(EntityInterface $node, $pid = NULL) {
// This is the case where the comment is in response to a node. Display the node.
elseif (user_access('access content')) {
$build['comment_node'] = node_view($node);
+ unset($build['comment_node']['#cache']);
}
// Should we show the reply box?
diff --git a/core/modules/comment/config/entity.view_mode.comment.full.yml b/core/modules/comment/config/entity.view_mode.comment.full.yml
index e48fbd7..abfc646 100644
--- a/core/modules/comment/config/entity.view_mode.comment.full.yml
+++ b/core/modules/comment/config/entity.view_mode.comment.full.yml
@@ -1,4 +1,5 @@
id: comment.full
label: Full comment
status: '0'
+cache: '1'
targetEntityType: comment
diff --git a/core/modules/comment/lib/Drupal/comment/CommentRenderController.php b/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
index c6b21f0..14585d6 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
@@ -79,9 +79,10 @@ protected function alterBuild(array &$build, EntityInterface $comment, EntityDis
$is_threaded = isset($comment->divs)
&& variable_get('comment_default_mode_' . $comment->bundle(), COMMENT_MODE_THREADED) == COMMENT_MODE_THREADED;
- // Add 'new' anchor if needed.
+ // Add 'new' anchor and disable render cache if needed.
if (!empty($comment->first_new)) {
$prefix .= "\n";
+ unset($build['#cache']);
}
// Add indentation div or close open divs as needed.
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
index 5bad9ea..fc91ed3 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
@@ -35,6 +35,7 @@
* uri_callback = "comment_uri",
* fieldable = TRUE,
* translatable = TRUE,
+ * render_cache = FALSE,
* route_base_path = "admin/structure/types/manage/{bundle}/comment",
* bundle_prefix = "comment_node_",
* entity_keys = {
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php
index 5fe19ba..6ae734e 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php
@@ -148,6 +148,8 @@ function testAnonymous() {
'post comments' => FALSE,
'skip comment approval' => FALSE,
));
+ \Drupal::entityManager()->getRenderController('node')->resetCache();
+ \Drupal::entityManager()->getRenderController('comment')->resetCache();
$this->drupalGet('node/' . $this->node->id());
$this->assertPattern('@
]*>Comments
@', 'Comments were displayed.');
$this->assertLink('Log in', 1, 'Link to log in was found.');
@@ -158,6 +160,8 @@ function testAnonymous() {
'post comments' => TRUE,
'skip comment approval' => TRUE,
));
+ \Drupal::entityManager()->getRenderController('node')->resetCache();
+ \Drupal::entityManager()->getRenderController('comment')->resetCache();
$this->drupalGet('node/' . $this->node->id());
$this->assertNoPattern('@]*>Comments
@', 'Comments were not displayed.');
$this->assertFieldByName('subject', '', 'Subject field found.');
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
index 0d27bf9..1d3b704 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
@@ -268,6 +268,7 @@ function setCommentsPerPage($number) {
*/
function setCommentSettings($name, $value, $message) {
variable_set($name . '_article', $value);
+ \Drupal::entityManager()->getRenderController('comment')->resetCache();
// Display status message.
$this->pass($message);
}
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
index 6a1c9de..5f997f7 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
@@ -121,6 +121,20 @@ public function id() {
/**
* {@inheritdoc}
*/
+ public function save() {
+ $return = parent::save();
+
+ // Reset the render cache for the target entity type.
+ if (\Drupal::entityManager()->hasController($this->targetEntityType, 'render')) {
+ \Drupal::entityManager()->getRenderController($this->targetEntityType)->resetCache();
+ }
+
+ return $return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getExportProperties() {
$names = array(
'id',
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php
index 8fe73cb..1541143 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php
@@ -58,6 +58,13 @@
public $status = TRUE;
/**
+ * Whether or not the rendered output of this view mode is cached by default.
+ *
+ * @var bool
+ */
+ public $cache = TRUE;
+
+ /**
* {@inheritdoc}
*/
public static function sort($a, $b) {
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
index aa93124..e89eaf6 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
@@ -96,8 +96,21 @@ public function view(EntityInterface $entity, $langcode, FieldInterface $items)
'#object' => $entity,
'#items' => $items->getValue(TRUE),
'#formatter' => $this->getPluginId(),
+ '#cache' => array('tags' => array())
);
+ // Gather cache tags from reference fields.
+ foreach ($items as $item) {
+ if (isset($item->format)) {
+ $info['#cache']['tags']['filter_format'] = $item->format;
+ }
+
+ if (isset($item->entity)) {
+ $info['#cache']['tags'][$item->entity->entityType()][] = $item->entity->id();
+ $info['#cache']['tags'][$item->entity->entityType() . '_view'] = TRUE;
+ }
+ }
+
$addition[$field_name] = array_merge($info, $elements);
}
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
index 4580e7b..a7cc0a8 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
@@ -34,8 +34,9 @@
*/
function setUp() {
parent::setUp();
- $this->installSchema('system', array('sequences', 'variable', 'config_snapshot'));
$this->installSchema('entity_test', 'entity_test');
+ $this->installSchema('system', array('sequences', 'variable', 'config_snapshot'));
+ $this->installSchema('user', array('users', 'users_roles'));
// Set default storage backend and configure the theme system.
$this->installConfig(array('field', 'system'));
diff --git a/core/modules/node/config/entity.view_mode.node.full.yml b/core/modules/node/config/entity.view_mode.node.full.yml
index af6d938..e4d8bd0 100644
--- a/core/modules/node/config/entity.view_mode.node.full.yml
+++ b/core/modules/node/config/entity.view_mode.node.full.yml
@@ -1,4 +1,5 @@
id: node.full
label: Full content
status: '0'
+cache: '1'
targetEntityType: node
diff --git a/core/modules/node/config/entity.view_mode.node.rss.yml b/core/modules/node/config/entity.view_mode.node.rss.yml
index 984b05f..0dbf7c1 100644
--- a/core/modules/node/config/entity.view_mode.node.rss.yml
+++ b/core/modules/node/config/entity.view_mode.node.rss.yml
@@ -1,4 +1,5 @@
id: node.rss
label: RSS
status: '0'
+cache: '1'
targetEntityType: node
diff --git a/core/modules/node/config/entity.view_mode.node.teaser.yml b/core/modules/node/config/entity.view_mode.node.teaser.yml
index 2089b94..636de15 100644
--- a/core/modules/node/config/entity.view_mode.node.teaser.yml
+++ b/core/modules/node/config/entity.view_mode.node.teaser.yml
@@ -1,4 +1,5 @@
id: node.teaser
label: Teaser
status: '1'
+cache: '1'
targetEntityType: node
diff --git a/core/modules/node/lib/Drupal/node/NodeRenderController.php b/core/modules/node/lib/Drupal/node/NodeRenderController.php
index e7fb844..c79f776 100644
--- a/core/modules/node/lib/Drupal/node/NodeRenderController.php
+++ b/core/modules/node/lib/Drupal/node/NodeRenderController.php
@@ -85,6 +85,10 @@ protected function alterBuild(array &$build, EntityInterface $entity, EntityDisp
if ($entity->id()) {
$build['#contextual_links']['node'] = array('node', array($entity->id()));
}
+
+ // The node 'submitted' info is not rendered in a standard way (renderable
+ // array) so we have to add a cache tag manually.
+ $build['#cache']['tags']['user'][] = $entity->uid;
}
}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index 6572ba9..3be598a 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
@@ -39,6 +39,7 @@
* uri_callback = "node_uri",
* fieldable = TRUE,
* translatable = TRUE,
+ * render_cache = FALSE,
* entity_keys = {
* "id" = "nid",
* "revision" = "vid",
diff --git a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
index 31d515f..95ce430 100644
--- a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
@@ -14,7 +14,7 @@
*/
class NodeConditionTest extends DrupalUnitTestBase {
- public static $modules = array('system', 'node', 'field');
+ public static $modules = array('system', 'node', 'entity', 'field');
public static function getInfo() {
return array(
diff --git a/core/modules/node/lib/Drupal/node/Tests/Views/RowPluginTest.php b/core/modules/node/lib/Drupal/node/Tests/Views/RowPluginTest.php
index 4924f56..b43fc3c 100644
--- a/core/modules/node/lib/Drupal/node/Tests/Views/RowPluginTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/Views/RowPluginTest.php
@@ -137,6 +137,7 @@ public function testRowPlugin() {
// Test with links disabled.
$view->rowPlugin->options['links'] = FALSE;
+ \Drupal::entityManager()->getRenderController('node')->resetCache();
$output = $view->preview();
$output = drupal_render($output);
$this->drupalSetContent($output);
@@ -146,6 +147,7 @@ public function testRowPlugin() {
// Test with links enabled.
$view->rowPlugin->options['links'] = TRUE;
+ \Drupal::entityManager()->getRenderController('node')->resetCache();
$output = $view->preview();
$output = drupal_render($output);
$this->drupalSetContent($output);
@@ -155,6 +157,7 @@ public function testRowPlugin() {
// Test with comments enabled.
$view->rowPlugin->options['comments'] = TRUE;
+ \Drupal::entityManager()->getRenderController('node')->resetCache();
$output = $view->preview();
$output = drupal_render($output);
foreach ($this->nodes as $node) {
@@ -165,6 +168,7 @@ public function testRowPlugin() {
// Test with comments disabled.
$view->rowPlugin->options['comments'] = FALSE;
+ \Drupal::entityManager()->getRenderController('node')->resetCache();
$output = $view->preview();
$output = drupal_render($output);
foreach ($this->nodes as $node) {
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 26f11a2..5586349 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -621,13 +621,15 @@ function node_revision_delete($revision_id) {
* @see node_menu()
*/
function node_show(EntityInterface $node, $message = FALSE) {
+ // For markup consistency with other pages, use node_view_multiple() rather than node_view().
+ $nodes = array('nodes' => node_view_multiple(array($node->id() => $node), 'full'));
+
if ($message) {
drupal_set_title(t('Revision of %title from %date', array('%title' => $node->label(), '%date' => format_date($node->getRevisionCreationTime()))), PASS_THROUGH);
+ // Don't use the render cache when a revision is displayed.
+ unset($nodes['nodes'][$node->id()]['#cache']);
}
- // For markup consistency with other pages, use node_view_multiple() rather than node_view().
- $nodes = array('nodes' => node_view_multiple(array($node->id() => $node), 'full'));
-
// Update the history table, stating that this user viewed this node.
if (module_exists('history')) {
history_write($node->id());
diff --git a/core/modules/search/config/entity.view_mode.node.search_index.yml b/core/modules/search/config/entity.view_mode.node.search_index.yml
index ed22c30..e12156d 100644
--- a/core/modules/search/config/entity.view_mode.node.search_index.yml
+++ b/core/modules/search/config/entity.view_mode.node.search_index.yml
@@ -1,4 +1,5 @@
id: node.search_index
label: Search index
status: '0'
+cache: '1'
targetEntityType: node
diff --git a/core/modules/search/config/entity.view_mode.node.search_result.yml b/core/modules/search/config/entity.view_mode.node.search_result.yml
index 1608657..776ada9 100644
--- a/core/modules/search/config/entity.view_mode.node.search_result.yml
+++ b/core/modules/search/config/entity.view_mode.node.search_result.yml
@@ -1,4 +1,5 @@
id: node.search_result
label: Search result
status: '0'
+cache: '1'
targetEntityType: node
diff --git a/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php b/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php
index 74fa8d9..981d6c7 100644
--- a/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php
+++ b/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php
@@ -16,12 +16,13 @@
*
* @var array
*/
- public static $modules = array('serialization', 'system', 'entity', 'field', 'entity_test', 'text', 'field_sql_storage');
+ public static $modules = array('serialization', 'system', 'entity', 'field', 'entity_test', 'text', 'field_sql_storage', 'user');
protected function setUp() {
parent::setUp();
$this->installSchema('entity_test', array('entity_test_mulrev', 'entity_test_mulrev_property_revision', 'entity_test_mulrev_property_data'));
+ $this->installSchema('user', array('users', 'users_roles'));
$this->installSchema('system', array('url_alias'));
$this->installConfig(array('field'));
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index c40fc6a..f532340 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -73,6 +73,17 @@ function statistics_node_view(EntityInterface $node, EntityDisplay $display, $vi
}
/**
+ * Implements hook_node_view_alter().
+ */
+function statistics_node_view_alter(&$build, EntityInterface $node, EntityDisplay $display) {
+ // If statistics were added to the node render array, we can't use the render
+ // cache.
+ if (isset($build['links']['statistics'])) {
+ unset($build['#cache']);
+ }
+}
+
+/**
* Implements hook_menu().
*/
function statistics_menu() {
diff --git a/core/modules/system/lib/Drupal/system/Form/DateFormatLocalizeResetForm.php b/core/modules/system/lib/Drupal/system/Form/DateFormatLocalizeResetForm.php
index d3de481..ab4de83 100644
--- a/core/modules/system/lib/Drupal/system/Form/DateFormatLocalizeResetForm.php
+++ b/core/modules/system/lib/Drupal/system/Form/DateFormatLocalizeResetForm.php
@@ -105,6 +105,7 @@ public function submitForm(array &$form, array &$form_state) {
foreach (config_get_storage_names_with_prefix('locale.config.' . $this->language->id . '.system.date_format.') as $config_id) {
$this->configFactory->get($config_id)->delete();
}
+ entity_render_cache_clear();
$form_state['redirect'] = 'admin/config/regional/date-time/locale';
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Action/ActionUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Action/ActionUnitTest.php
index 87e5113..757c9e9 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Action/ActionUnitTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Action/ActionUnitTest.php
@@ -18,7 +18,7 @@ class ActionUnitTest extends DrupalUnitTestBase {
/**
* {@inheritdoc}
*/
- public static $modules = array('system', 'field', 'user', 'action_test');
+ public static $modules = array('system','entity' , 'field', 'user', 'action_test');
/**
* The action manager.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
index f6a7056..de7b016 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -29,7 +29,6 @@ public static function getInfo() {
function setUp() {
parent::setUp();
- $this->installSchema('user', array('users_roles'));
$this->installSchema('system', array('variable', 'url_alias'));
$this->installConfig(array('language'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
index f9746d2..6b15158 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
@@ -31,7 +31,7 @@ public static function getInfo() {
public function setUp() {
parent::setUp();
- $this->installSchema('user', array('users_roles', 'users_data'));
+ $this->installSchema('user', array('users_data'));
$this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
$this->installSchema('comment', array('comment', 'node_comment_statistics'));
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
index 2c452d4..84231d3 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
@@ -43,7 +43,7 @@ public static function getInfo() {
public function setUp() {
parent::setUp();
- $this->installSchema('user', array('users_roles', 'users_data'));
+ $this->installSchema('user', array('users_data'));
$this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
$this->installSchema('comment', array('comment', 'node_comment_statistics'));
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index 77c816c..776ef60 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -35,7 +35,7 @@ public static function getInfo() {
public function setUp() {
parent::setUp();
- $this->installSchema('user', array('users_roles', 'users_data'));
+ $this->installSchema('user', array('users_data'));
$this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
$this->installSchema('entity_test', array(
'entity_test_mul',
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
index 34fb4cc..b1746ae 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
@@ -42,7 +42,7 @@ public function setUp() {
$this->entityManager = $this->container->get('plugin.manager.entity');
$this->state = $this->container->get('state');
- $this->installSchema('user', 'users');
+ $this->installSchema('user', array('users', 'users_roles'));
$this->installSchema('system', 'sequences');
$this->installSchema('entity_test', 'entity_test');
$this->installConfig(array('field'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php
index f00a35b..8e96d3b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php
@@ -37,7 +37,7 @@ public static function getInfo() {
*/
public function setUp() {
parent::setUp();
- $this->installSchema('user', array('users_roles', 'users_data'));
+ $this->installSchema('user', array('users_data'));
$this->installSchema('entity_test', array(
'entity_test_mul',
'entity_test_mul_property_data',
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/DateTimeTest.php b/core/modules/system/lib/Drupal/system/Tests/System/DateTimeTest.php
index 938c7e6..8794a88 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/DateTimeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/DateTimeTest.php
@@ -65,6 +65,7 @@ function testTimeZoneHandling() {
// Set time zone to Los Angeles time.
$config->set('timezone.default', 'America/Los_Angeles')->save();
+ \Drupal::entityManager()->getRenderController('node')->resetCache(array($node1->id(), $node2->id()));
// Confirm date format and time zone.
$this->drupalGet('node/' . $node1->id());
diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
index 6b1f0c5..91e4413 100644
--- a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
@@ -29,7 +29,7 @@ class TypedDataTest extends DrupalUnitTestBase {
*
* @var array
*/
- public static $modules = array('system', 'field', 'file');
+ public static $modules = array('system', 'entity', 'field', 'file');
public static function getInfo() {
return array(
diff --git a/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.full.yml b/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.full.yml
index 8902bc3..4ce40f1 100644
--- a/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.full.yml
+++ b/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.full.yml
@@ -1,4 +1,5 @@
id: entity_test_render.full
label: Full
status: '0'
+cache: '1'
targetEntityType: entity_test_render
diff --git a/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.test.yml b/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.test.yml
index a0d108b..310bceb 100644
--- a/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.test.yml
+++ b/core/modules/system/tests/modules/entity_test/config/entity.view_mode.entity_test_render.test.yml
@@ -1,4 +1,5 @@
id: entity_test_render.test
label: Test
status: '0'
+cache: '1'
targetEntityType: entity_test_render
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 05498f7..cd1086a 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -143,15 +143,17 @@ function entity_test_entity_bundle_info() {
function entity_test_entity_view_mode_info_alter(&$view_modes) {
$entity_info = entity_get_info();
foreach ($entity_info as $entity_type => $info) {
- if ($entity_info[$entity_type]['module'] == 'entity_test') {
+ if ($entity_info[$entity_type]['module'] == 'entity_test' && !isset($view_modes[$entity_type])) {
$view_modes[$entity_type] = array(
'full' => array(
'label' => t('Full object'),
'status' => TRUE,
+ 'cache' => TRUE,
),
'teaser' => array(
'label' => t('Teaser'),
'status' => TRUE,
+ 'cache' => TRUE,
),
);
}
diff --git a/core/modules/taxonomy/config/entity.view_mode.taxonomy_term.full.yml b/core/modules/taxonomy/config/entity.view_mode.taxonomy_term.full.yml
index 100547e..2666012 100644
--- a/core/modules/taxonomy/config/entity.view_mode.taxonomy_term.full.yml
+++ b/core/modules/taxonomy/config/entity.view_mode.taxonomy_term.full.yml
@@ -1,4 +1,5 @@
id: taxonomy_term.full
label: Taxonomy term page
status: '0'
+cache: '1'
targetEntityType: taxonomy_term
diff --git a/core/modules/user/config/entity.view_mode.user.compact.yml b/core/modules/user/config/entity.view_mode.user.compact.yml
index c27265b..c211e99 100644
--- a/core/modules/user/config/entity.view_mode.user.compact.yml
+++ b/core/modules/user/config/entity.view_mode.user.compact.yml
@@ -1,4 +1,5 @@
id: user.compact
label: Compact
status: '1'
+cache: '1'
targetEntityType: user
diff --git a/core/modules/user/config/entity.view_mode.user.full.yml b/core/modules/user/config/entity.view_mode.user.full.yml
index ac1ca20..343e909 100644
--- a/core/modules/user/config/entity.view_mode.user.full.yml
+++ b/core/modules/user/config/entity.view_mode.user.full.yml
@@ -1,4 +1,5 @@
id: user.full
label: User account
status: '0'
+cache: '1'
targetEntityType: user
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
index 4b79760..643f14e 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
@@ -121,6 +121,8 @@ function testPictureOnNodeComment() {
->set('features.node_user_picture', FALSE)
->set('features.comment_user_picture', FALSE)
->save();
+ \Drupal::entityManager()->getRenderController('node')->resetCache(array($node->id()));
+ \Drupal::entityManager()->getRenderController('comment')->resetCache();
$this->drupalGet('node/' . $node->id());
$this->assertNoRaw(file_uri_target($file->getFileUri()), 'User picture not found on node and comment.');
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php b/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
index 9350338..91285d6 100644
--- a/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
@@ -20,7 +20,7 @@
*
* @var array
*/
- public static $modules = array('user_test_views', 'user', 'system', 'field');
+ public static $modules = array('user_test_views', 'user', 'system', 'entity', 'field');
/**
* Users to use during this test.
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
index 95a543f..50e4fc0 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
@@ -20,7 +20,7 @@
*
* @var array
*/
- public static $modules = array('system', 'user', 'field');
+ public static $modules = array('system', 'user', 'entity', 'field');
/**
* Overrides \Drupal\views\Tests\ViewUnitTestBase::setUpFixtures().
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 78bbeca..9977931 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -1243,4 +1243,18 @@ public function mergeDefaultDisplaysOptions() {
public function uriRelationships() {
return $this->storage->uriRelationships();
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function relatedEntities() {
+ return $this->storage->relatedEntities();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function changed() {
+ return $this->storage->changed();
+ }
}