From fa326794892593aa7165354ab02e08e6bc2c47a6 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Fri, 1 Nov 2013 11:15:22 +0000
Subject: [PATCH] Issue #2094241 by moshe weitzmann, amateescu, Wim Leers:
 Cache tag the page cache.

---
 core/includes/common.inc                      | 34 ++++++++++++++++++-
 .../node/lib/Drupal/node/NodeViewBuilder.php  |  2 +-
 .../system/Tests/Bootstrap/PageCacheTest.php  | 24 +++++++++++++
 core/modules/system/system.module             |  1 +
 .../Controller/SystemTestController.php       | 11 ++++++
 .../system_test/system_test.routing.yml       |  7 ++++
 6 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5749ffefc5e9..07b5db6610b0 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3182,7 +3182,7 @@ function drupal_page_set_cache(Response $response, Request $request) {
         // because by the time it is read, the configuration might change.
         'page_compressed' => $page_compressed,
       ),
-      'tags' => array('content' => TRUE),
+      'tags' => array('content' => TRUE) + drupal_cache_tags_page_get(),
       'expire' => CacheBackendInterface::CACHE_PERMANENT,
       'created' => REQUEST_TIME,
     );
@@ -4218,6 +4218,38 @@ function drupal_render_collect_cache_tags($element, $tags = array()) {
   return $tags;
 }
 
+/**
+ * A #post_render callback at the top level of the $page array. Collects the
+ * tags for use in page cache.
+ *
+ * @param string $children
+ *   An HTML string of rendered output.
+ * @param array $elements
+ *   A render array.
+ *
+ * @return string
+ *   The same $children that was passed in - no modifications.
+ */
+function drupal_post_render_cache_tags_page_set($children, array $elements) {
+  if (drupal_page_is_cacheable()) {
+    $tags = &drupal_static('system_cache_tags_page', array());
+    $tags = drupal_render_collect_cache_tags($elements);
+  }
+  return $children;
+}
+
+/**
+ * Return the cache tags that were stored during drupal_render_page().
+ *
+ * @return array
+ *   An array of cache tags.
+ *
+ * @see drupal_post_render_cache_tags_page_set()
+ */
+function drupal_cache_tags_page_get() {
+  return drupal_static('system_cache_tags_page', array());
+}
+
 /**
  * Prepares an element for caching based on a query.
  *
diff --git a/core/modules/node/lib/Drupal/node/NodeViewBuilder.php b/core/modules/node/lib/Drupal/node/NodeViewBuilder.php
index 85511585d368..374ec6eff19e 100644
--- a/core/modules/node/lib/Drupal/node/NodeViewBuilder.php
+++ b/core/modules/node/lib/Drupal/node/NodeViewBuilder.php
@@ -88,7 +88,7 @@ protected function alterBuild(array &$build, EntityInterface $entity, EntityDisp
 
     // 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;
+    $build['#cache']['tags']['user'][] = $entity->getAuthorId();
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php
index 89d8ff4ae65d..aec3355fca71 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php
@@ -9,6 +9,7 @@
 
 use Symfony\Component\Routing\RequestContext;
 use Drupal\simpletest\WebTestBase;
+use Drupal\Core\Cache\Cache;
 
 /**
  * Enables the page cache and tests it with various HTTP requests.
@@ -41,6 +42,29 @@ function setUp() {
       ->save();
   }
 
+  /**
+   * Test that cache tags are properly persisted.
+   *
+   * Since tag based invalidation works, we know that our tag properly
+   * persisted.
+   */
+  function testPageCacheTags() {
+    $config = \Drupal::config('system.performance');
+    $config->set('cache.page.use_internal', 1);
+    $config->set('cache.page.max_age', 300);
+    $config->save();
+
+    $path = 'system-test/cache_tags_page';
+    $tags = array('system_test_cache_tags_page' => TRUE);
+    $this->drupalGet($path);
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+    $this->drupalGet($path);
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
+    Cache::invalidateTags($tags);
+    $this->drupalGet($path);
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+  }
+
   /**
    * Tests support for different cache items with different Accept headers.
    */
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index cf057b23d376..66e5a6ff18be 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -261,6 +261,7 @@ function system_element_info() {
     '#theme_wrappers' => array('form'),
   );
   $types['page'] = array(
+    '#post_render' => array('drupal_post_render_cache_tags_page_set'),
     '#show_messages' => TRUE,
     '#theme' => 'page',
     '#theme_wrappers' => array('html'),
diff --git a/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php b/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php
index db4302f15d5a..058aabedb421 100644
--- a/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php
+++ b/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php
@@ -38,6 +38,17 @@ public function lockExit() {
     return system_test_lock_exit();
   }
 
+  /**
+   * Set cache tag on on the returned render array.
+   */
+  function system_test_cache_tags_page() {
+    $build['main'] = array(
+      '#markup' => 'Cache tags page example',
+      '#cache' => array('tags' => array('system_test_cache_tags_page' => TRUE)),
+    );
+    return $build;
+  }
+
   /**
    * @todo Remove system_test_authorize_init_page().
    */
diff --git a/core/modules/system/tests/modules/system_test/system_test.routing.yml b/core/modules/system/tests/modules/system_test/system_test.routing.yml
index 4c6b56546ecf..660cfce92599 100644
--- a/core/modules/system/tests/modules/system_test/system_test.routing.yml
+++ b/core/modules/system/tests/modules/system_test/system_test.routing.yml
@@ -45,6 +45,13 @@ system_test.lock_exit:
   requirements:
     _access: 'TRUE'
 
+system_test.cache_tags_page:
+  path: '/system-test/cache_tags_page'
+  defaults:
+    _controller: '\Drupal\system_test\Controller\SystemTestController::system_test_cache_tags_page'
+  requirements:
+    _access: 'TRUE'
+
 system_test.authorize_init:
   path: '/system-test/authorize-init/{page_title}'
   defaults:
-- 
GitLab