/** * Adds a cache tag if the 'user.permissions' cache context is present. * * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The event to process. */ public function onRespond(FilterResponseEvent $event) { if (!$event->isMasterRequest()) { return; } if (!$this->currentUser->isAnonymous()) { return; } $response = $event->getResponse(); if (!$response instanceof CacheableResponseInterface) { return; } // The 'user.permissions' cache context ensures that if the permissions for // a role are modified, users are not served stale render cache content. // But, when entire responses are cached in reverse proxies, the value for // the cache context is never calculated, causing the stale response to not // be invalidated. Therefore, when varying by permissions and the current // user is the anonymous user, also add the cache tag for the 'anonymous' // role. if (in_array('user.permissions', $response->getCacheableMetadata()->getCacheContexts())) { $per_permissions_response_for_anon = new CacheableMetadata(); $per_permissions_response_for_anon->setCacheTags(['config:user.role.anonymous']); $response->addCacheableDependency($per_permissions_response_for_anon); } }
/** * {@inheritdoc} */ public function getCacheableMetadata($menu_name = NULL) { if (!$menu_name) { throw new \LogicException('No menu name provided for menu.active_trails cache context.'); } $cacheable_metadata = new CacheableMetadata(); return $cacheable_metadata->setCacheTags(["config:system.menu.{$menu_name}"]); }
/** * {@inheritdoc} */ public function getCacheableMetadata() { $cacheable_metadata = new CacheableMetadata(); $tags = []; foreach ($this->user->getRoles() as $rid) { $tags[] = "config:user.role.{$rid}"; } return $cacheable_metadata->setCacheTags($tags); }
/** * {@inheritdoc} */ public function getCacheableMetadata() { $cacheable_metadata = new CacheableMetadata(); // The permissions hash changes when: // - a user is updated to have different roles; $tags = ['user:' . $this->user->id()]; // - a role is updated to have different permissions. foreach ($this->user->getRoles() as $rid) { $tags[] = "config:user.role.{$rid}"; } return $cacheable_metadata->setCacheTags($tags); }
/** * Sets the '4xx-response' cache tag on 4xx responses. * * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The event to process. */ public function onRespond(FilterResponseEvent $event) { if (!$event->isMasterRequest()) { return; } $response = $event->getResponse(); if (!$response instanceof CacheableResponseInterface) { return; } if ($response->isClientError()) { $http_4xx_response_cacheability = new CacheableMetadata(); $http_4xx_response_cacheability->setCacheTags(['4xx-response']); $response->addCacheableDependency($http_4xx_response_cacheability); } }
/** * {@inheritdoc} */ public function getCacheableMetadata($operation = NULL) { $cacheable_metadata = new CacheableMetadata(); if (!\Drupal::moduleHandler()->getImplementations('node_grants')) { return $cacheable_metadata; } // The node grants may change if the user is updated. (The max-age is set to // zero below, but sites may override this cache context, and change it to a // non-zero value. In such cases, this cache tag is needed for correctness.) $cacheable_metadata->setCacheTags(['user:' . $this->user->id()]); // If the site is using node grants, this cache context can not be // optimized. return $cacheable_metadata->setCacheMaxAge(0); }
/** * {@inheritdoc} * * The entire HTML: takes a #type 'page' and wraps it in a #type 'html'. */ public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) { list($page, $title) = $this->prepare($main_content, $request, $route_match); if (!isset($page['#type']) || $page['#type'] !== 'page') { throw new \LogicException('Must be #type page'); } $page['#title'] = $title; // Now render the rendered page.html.twig template inside the html.html.twig // template, and use the bubbled #attached metadata from $page to ensure we // load all attached assets. $html = ['#type' => 'html', 'page' => $page]; // The special page regions will appear directly in html.html.twig, not in // page.html.twig, hence add them here, just before rendering html.html.twig. $this->buildPageTopAndBottom($html); // The three parts of rendered markup in html.html.twig (page_top, page and // page_bottom) must be rendered with drupal_render_root(), so that their // #post_render_cache callbacks are executed (which may attach additional // assets). // html.html.twig must be able to render the final list of attached assets, // and hence may not execute any #post_render_cache_callbacks (because they // might add yet more assets to be attached), and therefore it must be // rendered with drupal_render(), not drupal_render_root(). $this->renderer->render($html['page'], TRUE); if (isset($html['page_top'])) { $this->renderer->render($html['page_top'], TRUE); } if (isset($html['page_bottom'])) { $this->renderer->render($html['page_bottom'], TRUE); } $content = $this->renderer->render($html); // Set the generator in the HTTP header. list($version) = explode('.', \Drupal::VERSION, 2); $response = new CacheableResponse($content, 200, ['Content-Type' => 'text/html; charset=UTF-8', 'X-Generator' => 'Drupal ' . $version . ' (https://www.drupal.org)']); // Bubble the cacheability metadata associated with the rendered render // arrays to the response. foreach (['page_top', 'page', 'page_bottom'] as $region) { if (isset($html[$region])) { $response->addCacheableDependency(CacheableMetadata::createFromRenderArray($html[$region])); } } // Also associate the "rendered" cache tag. This allows us to invalidate the // entire render cache, regardless of the cache bin. $default = new CacheableMetadata(); $default->setCacheTags(['rendered']); $response->addCacheableDependency($default); return $response; }