diff --git a/core/includes/common.inc b/core/includes/common.inc index dfd20fa..8f8ab08 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4039,7 +4039,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); } @@ -4087,6 +4087,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 fe30114..5f92cc1 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)); + } + 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($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 33a62ce..b1f87ea 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -13,6 +13,7 @@ use Drupal\Core\TypedData\TypedDataInterface; use IteratorAggregate; use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Cache\Cache; /** * Defines a base entity class. @@ -349,6 +350,7 @@ public function getTranslationLanguages($include_default = TRUE) { * Implements \Drupal\Core\Entity\EntityInterface::save(). */ public function save() { + $this->changed(); return \Drupal::entityManager()->getStorageController($this->entityType)->save($this); } @@ -356,6 +358,7 @@ public function save() { * Implements \Drupal\Core\Entity\EntityInterface::delete(). */ public function delete() { + $this->changed(); if (!$this->isNew()) { \Drupal::entityManager()->getStorageController($this->entityType)->delete(array($this->id() => $this)); } @@ -637,4 +640,43 @@ public function initTranslation($langcode) { // http://drupal.org/node/2004244 } + /** + * {@inheritdoc} + */ + public function getDefaultCacheTags() { + return array(); + } + + + /** + * {@inheritdoc} + */ + public function relationships() { + return array(); + } + + /** + * {@inheritdoc} + */ + public function changed() { + $entity_type = $this->entityType(); + $id = $this->id(); + $tags = $this->getDefaultCacheTags(); + + $tags += array( + $entity_type => array($id), + $entity_type . '_view' => array($id) + ); + foreach ($this->relationships() as $related_entity) { + $related_entity_type = $related_entity->entityType(); + if (!isset($tags[$related_entity_type . '_view'])) { + $tags[$related_entity_type . '_view'] = array(); + + } + $tags[$related_entity_type . '_view'][] = $related_entity->id(); + } + + Cache::deleteTags($tags); + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php index a3ffcb9..2279ace 100644 --- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php +++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php @@ -626,4 +626,27 @@ public function initTranslation($langcode) { $this->decorated->initTranslation($langcode); } + /** + * {@inheritdoc} + */ + public function getDefaultCacheTags() { + return array(); + } + + /** + * {@inheritdoc} + * + * @return array + */ + public function relationships() { + return array(); + } + + /** + * {@inheritdoc} + */ + public function changed(array $tags = array()) { + $this->decorated->changed($tags); + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php index 36fb318..971fa54 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormController.php +++ b/core/lib/Drupal/Core/Entity/EntityFormController.php @@ -378,7 +378,10 @@ public function submit(array $form, array &$form_state) { * A reference to a keyed array containing the current state of the form. */ public function save(array $form, array &$form_state) { - // @todo Perform common save operations. + // Clear the render cache. + if (\Drupal::entityManager()->hasController($this->entity->entityType(), 'render')) { + \Drupal::entityManager()->getRenderController($this->entity->entityType())->resetCache(); + } } /** diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index e965b8e..b671b21 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -326,4 +326,23 @@ public function isTranslatable(); */ public function initTranslation($langcode); + /** + * @todo + * + * @return array + */ + public function relationships(); + + /** + * @todo + */ + public function changed(); + + /** + * @todo + * + * @return array + */ + public function getDefaultCacheTags(); + } diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index a6768e8..0642393 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -175,6 +175,14 @@ protected function init() { unset($this->langcode); } + public function save() { + parent::save(); + } + + public function delete() { + parent::delete(); + } + /** * Clear entity translation object cache to remove stale references. */ diff --git a/core/lib/Drupal/Core/Entity/EntityRenderController.php b/core/lib/Drupal/Core/Entity/EntityRenderController.php index cd92f52..f08f4b3 100644 --- a/core/lib/Drupal/Core/Entity/EntityRenderController.php +++ b/core/lib/Drupal/Core/Entity/EntityRenderController.php @@ -22,8 +22,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 +91,22 @@ 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. + $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) { + $return['#cache'] = array( + 'keys' => array('entity_view', $this->entityType ,$entity->id(), $view_mode), + 'granularity' => DRUPAL_CACHE_PER_ROLE, + 'bin' => $this->cacheBin, + 'tags' => array( + $this->entityType . '_view' => TRUE, + $this->entityType => array($entity->id()), + "{$this->entityType}:{$entity->bundle()}" => TRUE, + ), + ); + } + return $return; } @@ -164,4 +209,36 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la return $build; } + + /** + * {@inheritdoc} + */ + public function resetCache(array $entities = NULL) { + if (isset($entities)) { + $tags = array(); + foreach ($entities as $entity) { + $id = $entity->id(); + $tags[$this->entityType][$id] = $id; + + // @todo Remove when all entities are converted to EntityNG. + if ($entity->getPropertyDefinitions() === NULL) { + continue; + } + + // Add all the referenced entity types and IDs to the tags that will be + // cleared. + foreach ($entity->getPropertyDefinitions() as $name => $definition) { + if ($definition['type'] == 'entity_reference_field' && $field_values = $entity->get($name)->getValue()) { + foreach (array_filter($field_values) as $value) { + $tags[$definition['settings']['target_type']][$value['target_id']] = $value['target_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..88e1461 100644 --- a/core/lib/Drupal/Core/Entity/EntityRenderControllerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityRenderControllerInterface.php @@ -75,4 +75,12 @@ 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 $entities + * (optional) If specified, the cache is reset for the given entities only. + */ + public function resetCache(array $entities = NULL); } diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php index ef25376..0b3521f 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php @@ -112,6 +112,8 @@ public function validate(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $feed = $this->entity; $insert = (bool) $feed->id(); if (!empty($form_state['values']['category'])) { 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/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php index 2f18d5b..83696a4 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php @@ -158,6 +158,8 @@ public function submit(array $form, array &$form_state) { * Overrides \Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $block = $this->entity; $insert = empty($block->id->value); $block->save(); diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php index cf88f5d..63bf902 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php @@ -87,6 +87,8 @@ public function form(array $form, array &$form_state) { * Overrides \Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $block_type = $this->entity; $status = $block_type->save(); diff --git a/core/modules/block/lib/Drupal/block/BlockRenderController.php b/core/modules/block/lib/Drupal/block/BlockRenderController.php index 45a85d9..fb7edfb 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; } + /** + * Implements \Drupal\Core\Entity\EntityRenderControllerInterface::resetCache(). + */ + public function resetCache(array $entities = 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.admin.inc b/core/modules/comment/comment.admin.inc index ac186cc..bd8a1f5 100644 --- a/core/modules/comment/comment.admin.inc +++ b/core/modules/comment/comment.admin.inc @@ -211,6 +211,7 @@ function comment_admin_overview_submit($form, &$form_state) { } drupal_set_message(t('The update has been performed.')); $form_state['redirect'] = 'admin/content/comment'; + Drupal::entityManager()->getRenderController('comment')->resetCache(array($comment)); cache_invalidate_tags(array('content' => TRUE)); } @@ -258,7 +259,13 @@ function comment_multiple_delete_confirm($form, &$form_state) { */ function comment_multiple_delete_confirm_submit($form, &$form_state) { if ($form_state['values']['confirm']) { - entity_delete_multiple('comment', array_keys($form_state['values']['comments'])); + $entity_manager = Drupal::entityManager(); + + $controller = $entity_manager->getStorageController('comment'); + $entities = $controller->loadMultiple(array_keys($form_state['values']['comments'])); + $controller->delete($entities); + + $entity_manager->getRenderController('comment')->resetCache($entities); cache_invalidate_tags(array('content' => TRUE)); $count = count($form_state['values']['comments']); watchdog('content', 'Deleted @count comments.', array('@count' => $count)); @@ -315,6 +322,7 @@ function comment_confirm_delete_submit($form, &$form_state) { drupal_set_message(t('The comment and all its replies have been deleted.')); watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->id())); // Clear the cache so an anonymous user sees that his comment was deleted. + Drupal::entityManager()->getRenderController('comment')->resetCache(array($comment)); cache_invalidate_tags(array('content' => TRUE)); $form_state['redirect'] = "node/{$comment->nid->target_id}"; diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc index 4998f83..9a913ee 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/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php index 2264290..dec3833 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php @@ -315,6 +315,8 @@ public function preview(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $node = node_load($form_state['values']['nid']); $comment = $this->entity; 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/Controller/CommentController.php b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php index fe340cf..28d6e17 100644 --- a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php +++ b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php @@ -84,6 +84,7 @@ public function commentApprove(Request $request, CommentInterface $comment) { $comment->status->value = COMMENT_PUBLISHED; $comment->save(); + \Drupal::entityManager()->getRenderController('comment')->resetCache(array($comment)); drupal_set_message(t('Comment approved.')); $permalink_uri = $comment->permalink(); diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Action/SaveComment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Action/SaveComment.php index 6127c8d..5ca8f25 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/Action/SaveComment.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/Action/SaveComment.php @@ -28,6 +28,7 @@ class SaveComment extends ActionBase { */ public function execute($comment = NULL) { $comment->save(); + \Drupal::entityManager()->getRenderController('comment')->resetCache(array($comment)); Cache::invalidateTags(array('content' => TRUE)); } 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 27dbf17..f3aa91c 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 @@ -315,6 +315,8 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { */ public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { $this->releaseThreadLock(); + + // Update the {node_comment_statistics} table prior to executing the hook. $storage_controller->updateNodeStatistics($this->nid->target_id); if ($this->status->value == COMMENT_PUBLISHED) { @@ -323,6 +325,29 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $ } /** + * {@inheritdoc} + */ + public function relationships() { + $relationships = array($this->getNode()); + if ($this->hasParentComment()) { + $relationships[] = $this->getParentComment(); + } + return $relationships; + } + + protected function getNode() { + return $this->nid->entity; + } + + protected function hasParentComment() { + return $this->pid->entity !== NULL; + } + + protected function getParentComment() { + return $this->pid->entity; + } + + /** * Release the lock acquired for the thread in preSave(). */ protected function releaseThreadLock() { diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php index f4ef8cf..f6d595c 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->nid); $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->nid); $this->assertNoPattern('@]*>Comments@', 'Comments were not displayed.'); $this->assertFieldByName('subject', '', 'Subject field found.'); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php index 2b506ce..67854d4 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php @@ -61,6 +61,8 @@ function testCommentClasses() { )); $comment->save(); + \Drupal::entityManager()->getRenderController('node')->resetCache(array($comment)); + // Adjust the current/viewing user. switch ($case['user']) { case 'anonymous': diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php index a0f0cdc..082b746 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php @@ -210,6 +210,9 @@ function setEnvironment(array $info) { // Update current environment. $current = $info; + // Clear the render cache. + entity_render_cache_clear(); + return $info; } diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php index 0332dd7..efffc66 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/config/tests/config_test/lib/Drupal/config_test/ConfigTestFormController.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestFormController.php index 119774b..ebc6596 100644 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestFormController.php +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestFormController.php @@ -69,6 +69,8 @@ public function form(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $entity = $this->entity; $status = $entity->save(); diff --git a/core/modules/contact/lib/Drupal/contact/CategoryFormController.php b/core/modules/contact/lib/Drupal/contact/CategoryFormController.php index 5f2e78c..2ec70d7 100644 --- a/core/modules/contact/lib/Drupal/contact/CategoryFormController.php +++ b/core/modules/contact/lib/Drupal/contact/CategoryFormController.php @@ -94,6 +94,8 @@ public function validate(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $category = $this->entity; $status = $category->save(); diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php index a4abbac..c596df6 100644 --- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php +++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php @@ -132,6 +132,7 @@ public function preview(array $form, array &$form_state) { */ public function save(array $form, array &$form_state) { global $user; + parent::save($form, $form_state); $language_interface = language(Language::TYPE_INTERFACE); $message = $this->entity; diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php index 99008e2..fa1276a 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php +++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php @@ -126,7 +126,14 @@ public function save() { if (empty($this->id)) { $this->id = $this->id(); } - return parent::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; } /** diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php index 4fe2c12..9ab7573 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php +++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeBase.php @@ -57,4 +57,10 @@ */ public $status = FALSE; + /** + * Whether or not the rendered output of this view mode is cached by default. + * + * @var bool + */ + public $cache = TRUE; } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php index cbfb636..3720737 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php @@ -577,6 +577,14 @@ public function allowBundleRename() { /** * {@inheritdoc} */ + public function getDefaultCacheTags() { + // Return the entity_type this instance is attached to. + return array("{$this->entity_type}:{$this->bundle}" => TRUE); + } + + /** + * {@inheritdoc} + */ public function offsetExists($offset) { return (isset($this->{$offset}) || $offset == 'field_id' || $offset == 'field_name'); } 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 fa780a5..0ac08a7 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 @@ -95,8 +95,21 @@ public function view(EntityInterface $entity, $langcode, array $items) { '#object' => $entity, '#items' => $items, '#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_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php index 841c056..89ef4f2 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php @@ -150,6 +150,8 @@ protected function saveDisplayModeSettings($display_mode_settings) { $bundle_settings = field_bundle_settings($this->entity_type, $this->bundle); $bundle_settings['view_modes'] = NestedArray::mergeDeep($bundle_settings['view_modes'], $display_mode_settings); field_bundle_settings($this->entity_type, $this->bundle, $bundle_settings); + // Clear the render cache for this entity type. + \Drupal::entityManager()->getRenderController($this->entity_type)->resetCache(); } /** diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php index 26264ac..0f2fc8e 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php @@ -187,6 +187,7 @@ public function submitForm(array &$form, array &$form_state) { foreach ($form_state['values']['instance'] as $key => $value) { $this->instance[$key] = $value; } + $this->instance->save(); drupal_set_message(t('Saved %label configuration.', array('%label' => $this->instance->label()))); diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php index a5d8790..c32eb24 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php @@ -345,7 +345,7 @@ function assertNodeViewTextHelper(EntityInterface $node, $view_mode, $text, $mes // Render a cloned node, so that we do not alter the original. $clone = clone $node; - $element = node_view($clone, $view_mode); + $element = entity_view($clone, $view_mode, NULL, TRUE); $output = drupal_render($element); $this->verbose(t('Rendered node - view mode: @view_mode', array('@view_mode' => $view_mode)) . '
'. $output); diff --git a/core/modules/file/config/entity.view_mode.file.full.yml b/core/modules/file/config/entity.view_mode.file.full.yml index 60808f9..4d4ed1f 100644 --- a/core/modules/file/config/entity.view_mode.file.full.yml +++ b/core/modules/file/config/entity.view_mode.file.full.yml @@ -1,4 +1,5 @@ id: file.full label: File default status: '0' +cache: '1' targetEntityType: file diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php index e7775ad..7950da1 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php @@ -231,6 +231,7 @@ function testImageFieldDefaultImage() { $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field", $edit, t('Save field settings')); // Clear field info cache so the new default image is detected. field_info_cache_clear(); + \Drupal::entityManager()->getRenderController('node')->resetCache(); $field = field_info_field($field_name); $image = file_load($field['settings']['default_image']); $this->assertTrue($image->isPermanent(), 'The default image status is permanent.'); diff --git a/core/modules/menu/lib/Drupal/menu/MenuFormController.php b/core/modules/menu/lib/Drupal/menu/MenuFormController.php index a709d2e..78ef8c9 100644 --- a/core/modules/menu/lib/Drupal/menu/MenuFormController.php +++ b/core/modules/menu/lib/Drupal/menu/MenuFormController.php @@ -145,6 +145,8 @@ public function languageConfigurationSubmit(array &$form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $menu = $this->entity; $system_menus = menu_list_system_menus(); diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php index 8eb4458..0d6b3b5 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php @@ -274,8 +274,9 @@ public function submit(array $form, array &$form_state) { * Overrides EntityFormController::save(). */ public function save(array $form, array &$form_state) { - $menu_link = $this->entity; + parent::save($form, $form_state); + $menu_link = $this->entity; $saved = $menu_link->save(); if ($saved) { 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/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index 814d937..fd91c51 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -433,6 +433,8 @@ public function unpublish(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $node = $this->entity; $insert = empty($node->nid); $node->save(); diff --git a/core/modules/node/lib/Drupal/node/NodeRenderController.php b/core/modules/node/lib/Drupal/node/NodeRenderController.php index a58a96f..1305bfd 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 (!empty($entity->nid)) { $build['#contextual_links']['node'] = array('node', array($entity->nid)); } + + // 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/Tests/NodeRevisionsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php index dd2df8d..23718b8 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php @@ -141,6 +141,7 @@ function testRevisions() { $new_node_revision->setNewRevision(); $new_node_revision->isDefaultRevision = FALSE; $new_node_revision->save(); + \Drupal::entityManager()->getRenderController('node')->resetCache(array($node)); $this->drupalGet("node/$node->nid"); $this->assertNoText($new_body, 'Revision body text is not present on default version of node.'); 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 e836700..553d011 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -621,12 +621,16 @@ 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')) { @@ -1828,7 +1832,7 @@ function _node_index_node(EntityInterface $node) { foreach ($languages as $language) { // Render the node. - $build = node_view($node, 'search_index', $language->id); + $build = entity_view($node, 'search_index', $language->langcode, TRUE); unset($build['#theme']); $node->rendered = drupal_render($build); diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingFormController.php b/core/modules/picture/lib/Drupal/picture/PictureMappingFormController.php index 4b93dc5..55f969b 100644 --- a/core/modules/picture/lib/Drupal/picture/PictureMappingFormController.php +++ b/core/modules/picture/lib/Drupal/picture/PictureMappingFormController.php @@ -134,6 +134,8 @@ public function validate(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $picture_mapping = $this->entity; $picture_mapping->save(); diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php index 345ae8c..61e9a2a 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php @@ -348,6 +348,7 @@ function saveComment($nid, $uid, $contact = NULL, $pid = 0) { $comment = entity_create('comment', $values); $comment->save(); + \Drupal::entityManager()->getRenderController('comment')->resetCache(array($comment)); return $comment; } } 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/shortcut/lib/Drupal/shortcut/ShortcutFormController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php index 1e25679..0eed29e 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php @@ -73,6 +73,8 @@ public function validate(array $form, array &$form_state) { * Overrides \Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $entity = $this->entity; $is_new = !$entity->getOriginalID(); $entity->save(); diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module index 0c4580c..dbe529f 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/System/DateTimeTest.php b/core/modules/system/lib/Drupal/system/Tests/System/DateTimeTest.php index b9752b4..ab4cb04 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('default', 'America/Los_Angeles')->save(); + \Drupal::entityManager()->getRenderController('node')->resetCache(array($node1, $node2)); // Confirm date format and time zone. $this->drupalGet("node/$node1->nid"); 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/lib/Drupal/entity_test/EntityTestFormController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php index 1dbb859..ae89d38 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php @@ -80,6 +80,8 @@ public function submit(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $entity = $this->entity; $is_new = $entity->isNew(); $entity->save(); 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/taxonomy/config/entity.view_mode.taxonomy_vocabulary.full.yml b/core/modules/taxonomy/config/entity.view_mode.taxonomy_vocabulary.full.yml index bb47091..8961a6f 100644 --- a/core/modules/taxonomy/config/entity.view_mode.taxonomy_vocabulary.full.yml +++ b/core/modules/taxonomy/config/entity.view_mode.taxonomy_vocabulary.full.yml @@ -1,4 +1,5 @@ id: vocabulary.full label: Taxonomy vocabulary status: '0' +cache: '1' targetEntityType: taxonomy_vocabulary diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php index 4f4043a..bcf3d85 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php @@ -155,6 +155,8 @@ public function buildEntity(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $term = $this->entity; switch ($term->save()) { diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php index 9dbf118..202c8de 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php @@ -342,6 +342,7 @@ function testTermInterface() { // Check that it does NOT show a description when description is blank. $term->description = ''; $term->save(); + \Drupal::entityManager()->getRenderController('taxonomy_term')->resetCache(array($term)); $this->drupalGet('taxonomy/term/' . $term->id()); $this->assertNoPattern('|class="taxonomy-term-description"|', 'Term page did not display the term description when description was blank.'); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php index db8c145..2b5fbd1 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php @@ -145,6 +145,8 @@ public function submit(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $vocabulary = $this->entity; // Prevent leading and trailing spaces in vocabulary names. diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc index 62defe2..04c8e51 100644 --- a/core/modules/taxonomy/taxonomy.admin.inc +++ b/core/modules/taxonomy/taxonomy.admin.inc @@ -420,13 +420,15 @@ function taxonomy_term_confirm_delete($form, &$form_state, Term $term) { * @see taxonomy_term_confirm_delete() */ function taxonomy_term_confirm_delete_submit($form, &$form_state) { - entity_delete_multiple('taxonomy_term', array($form_state['values']['tid'])); + $entity = taxonomy_term_load($form_state['values']['tid']); + $entity->delete(); taxonomy_check_vocabulary_hierarchy($form_state['taxonomy']['vocabulary'], $form_state['values']); drupal_set_message(t('Deleted term %name.', array('%name' => $form_state['values']['name']))); watchdog('taxonomy', 'Deleted term %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE); if (!isset($_GET['destination'])) { $form_state['redirect'] = 'admin/structure/taxonomy'; } + Drupal::entityManager()->getRenderController('taxonomy_term')->resetCache(array($entity)); cache_invalidate_tags(array('content' => TRUE)); return; } 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/ProfileFormController.php b/core/modules/user/lib/Drupal/user/ProfileFormController.php index 53b29b1..1198ddd 100644 --- a/core/modules/user/lib/Drupal/user/ProfileFormController.php +++ b/core/modules/user/lib/Drupal/user/ProfileFormController.php @@ -41,6 +41,8 @@ public function submit(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::save(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $account = $this->entity; $account->save(); $form_state['values']['uid'] = $account->id(); diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php index 116f6c2..d29e7e7 100644 --- a/core/modules/user/lib/Drupal/user/RegisterFormController.php +++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php @@ -89,6 +89,8 @@ public function submit(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::submit(). */ public function save(array $form, array &$form_state) { + parent::save($form, $form_state); + $account = $this->entity; $pass = $account->pass; $admin = $form_state['values']['administer_users']; diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php index f4a0662..280b645 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()->getStorageController('node')->resetCache(array($node)); + \Drupal::entityManager()->getStorageController('comment')->resetCache(); $this->drupalGet('node/' . $node->nid); $this->assertNoRaw(file_uri_target($file->getFileUri()), 'User picture not found on node and comment.'); diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc index bb486ff..4e77d90 100644 --- a/core/modules/user/user.admin.inc +++ b/core/modules/user/user.admin.inc @@ -195,8 +195,9 @@ function user_admin_permissions_submit($form, &$form_state) { drupal_set_message(t('The changes have been saved.')); - // Clear the cached pages and blocks. + // Clear cached pages, blocks and rendered entities. cache_invalidate_tags(array('content' => TRUE)); + entity_render_cache_clear(); } /**