Page caching is far more flexible in Drupal 8. Sites and modules can implement their own policies for when requests and responses are cacheable. For modules, a key change is the removal of drupal_page_is_cacheable().
Preventing a response from being cached
Before
drupal_page_is_cacheable(FALSE)
After (preferred method):
Implement Drupal\Core\PageCache\ResponsePolicyInterface and register it as a service with the tag page_cache_response_policy.
services:
image.page_cache_request_policy.deny_private_image_style_download:
class: Drupal\image\PageCache\DenyPrivateImageStyleDownload
arguments: ['@current_route_match']
tags:
- { name: page_cache_response_policy }
/**
* Cache policy for image preview page.
*
* This policy rule denies caching of responses generated by the
* entity.image.preview route.
*/
class DenyPrivateImageStyleDownload implements ResponsePolicyInterface {
/**
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Constructs a deny image preview page cache policy.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The current route match.
*/
public function __construct(RouteMatchInterface $route_match) {
$this->routeMatch = $route_match;
}
/**
* {@inheritdoc}
*/
public function check(Response $response, Request $request) {
if ($this->routeMatch->getRouteName() === 'image.style_private') {
return static::DENY;
}
}
}
After (fallback method):
If it is impossible to decide cacheability using either a RequestPolicyInterface (preferred) or ResponsePolicyInterface, use the global kill-switch to disable the page cache:
\Drupal::service('page_cache_kill_switch')->trigger();
Allowing a request to be served from the cache (even for users with an open session)
(See the toolbar module)
Before (only possible with ugly workaround):
drupal_page_is_cacheable(TRUE);
// If we have a cache, serve it.
// @see \Drupal\Core\DrupalKernel::handlePageCache()
$request = \Drupal::request();
$response = drupal_page_get_cache($request);
if ($response) {
$response->headers->set('X-Drupal-Cache', 'HIT');
drupal_serve_page_from_cache($response, $request);
$response->prepare($request);
$response->send();
// We are done.
exit;
}
After
Implement Drupal\Core\PageCache\RequestPolicyInterface and register it as a service with the tag page_cache_request_policy.
Note that the request-policy check runs very early. In particular it is not possible to determine the logged in user. Also the current route match is not yet present when the check runs. Therefore, request-policy checks should be designed in a way such that they do not depend on any other service and only take in account the information present on the incoming request.
services:
toolbar.page_cache_request_policy.toolbar_path:
class: Drupal\toolbar\PageCache\IsToolbarPath
tags:
- { name: page_cache_request_policy }
/**
* Cache policy for the toolbar page cache service.
*
* This policy allows caching of requests directed to /toolbar/subtrees/{hash}
* even for authenticated users.
*/
class IsToolbarPath implements RequestPolicyInterface {
/**
* Test whether this request goes to /toolbar/subtrees.
*/
public function check(Request $request) {
$path = $request->getPathInfo();
$toolbar_path_offset = strpos($path, '/toolbar/subtrees/');
if ($toolbar_path_offset !== FALSE) {
// Also accept paths matching at the first slash in order to cater for
// sites using language prefixes.
$second_slash = strpos($path, '/', 1);
if ($toolbar_path_offset === 0 || $toolbar_path_offset === $second_slash) {
return static::ALLOW;
}
}
}
}