.../Core/Render/MainContent/HtmlRenderer.php | 4 +++
.../src/EventSubscriber/SmartCacheSubscriber.php | 32 ++++++++++++++++++++--
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
index 4b5f0a5..6092a28 100644
--- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
+++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
@@ -142,6 +142,10 @@ public function renderResponse(array $main_content, Request $request, RouteMatch
// @see \Drupal\Core\Render\HtmlResponseAttachmentsProcessor.
$render_context = new RenderContext();
$this->renderer->executeInRenderContext($render_context, function() use (&$html) {
+ // RendererInterface::render() renders the $html render array, it updates
+ // $html by reference. We don't care about the return value (which is just
+ // $html['#markup']), but about the resulting render array.
+ // @todo Simplify this when https://www.drupal.org/node/2495001 lands.
$this->renderer->render($html);
});
if (!$render_context->isEmpty()) {
diff --git a/core/modules/smart_cache/src/EventSubscriber/SmartCacheSubscriber.php b/core/modules/smart_cache/src/EventSubscriber/SmartCacheSubscriber.php
index 4b825a0..2e58521 100644
--- a/core/modules/smart_cache/src/EventSubscriber/SmartCacheSubscriber.php
+++ b/core/modules/smart_cache/src/EventSubscriber/SmartCacheSubscriber.php
@@ -23,11 +23,32 @@
/**
* Uses the SmartCache as early as possible, to avoid as much work as possible.
*
+ * SmartCache is able to cache so much because it exploits cache contexts: the
+ * cache contexts that are present capture the variations of every component of
+ * the page. That, combined with the fact that cacheability metadata is bubbled,
+ * means that the cache contexts at the page level represent the complete set of
+ * contexts that the page varies by.
+ *
+ * The reason SmartCache is implemented as two event subscribers (a late REQUEST
+ * subscriber immediately after routing for cache hits, and an early RESPONSE
+ * subscriber for cache misses) is because many cache contexts can only be
+ * evaluated after routing. (Examples: 'user', 'user.permissions', 'route' …)
+ * Consequently, it is impossible to implement SmartCache as a kernel middleware
+ * that simply caches per URL.
+ *
* @see \Drupal\Core\Render\MainContent\HtmlRenderer
*/
class SmartCacheSubscriber implements EventSubscriberInterface {
/**
+ * Attribute name of the Smart Cache request policy result.
+ *
+ * @see onRouteMatch()
+ * @see onRespond()
+ */
+ const SMART_CACHE_REQUEST_POLICY_RESULT = '_smart_cache_request_policy_result';
+
+ /**
* The cache contexts manager.
*
* @var \Drupal\Core\Cache\Context\CacheContextsManager
@@ -92,8 +113,12 @@ public function __construct(CacheContextsManager $cache_contexts_manager, CacheB
*/
public function onRouteMatch(GetResponseEvent $event) {
// Don't cache the HTML response if the SmartCache request policies are not
- // met.
- if ($this->requestPolicy->check($event->getRequest()) === RequestPolicyInterface::DENY) {
+ // met. Store the result in a request attribute, so that onResponse() does
+ // not have to redo the request policy check.
+ $request = $event->getRequest();
+ $request_policy_result = $this->requestPolicy->check($request);
+ $event->getRequest()->attributes->set(self::SMART_CACHE_REQUEST_POLICY_RESULT, $request_policy_result);
+ if ($request_policy_result === RequestPolicyInterface::DENY) {
return;
}
@@ -137,8 +162,9 @@ public function onResponse(FilterResponseEvent $event) {
// Don't cache the HTML response if the SmartCache request & response
// policies are not met.
+ // @see onRouteMatch()
$request = $event->getRequest();
- if ($this->requestPolicy->check($request) === RequestPolicyInterface::DENY || $this->responsePolicy->check($response, $request) === ResponsePolicyInterface::DENY) {
+ if ($request->attributes->get(self::SMART_CACHE_REQUEST_POLICY_RESULT) === RequestPolicyInterface::DENY || $this->responsePolicy->check($response, $request) === ResponsePolicyInterface::DENY) {
return;
}