Commit 5e8523ec authored by effulgentsia's avatar effulgentsia

Issue #2429617 by Wim Leers, Fabianx, Berdir, yched, dawehner, effulgentsia,...

Issue #2429617 by Wim Leers, Fabianx, Berdir, yched, dawehner, effulgentsia, catch, borisson_, jhodgdon, martin107, torgosPizza: Make D8 2x as fast: Dynamic Page Cache: context-dependent page caching (for *all* users!)
parent 472403c2
......@@ -312,6 +312,10 @@ Database Logging module
DateTime module
- Matthew Donadio 'mpdonadio' https://www.drupal.org/u/mpdonadio
Dynamic Page Cache module
- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx
- Wim Leers 'Wim Leers' https://www.drupal.org/u/wim-leers
Email module
- Nils Destoop 'zuuperman' https://www.drupal.org/u/zuuperman
......
......@@ -73,6 +73,7 @@
"drupal/core-uuid": "self.version",
"drupal/datetime": "self.version",
"drupal/dblog": "self.version",
"drupal/dynamic_page_cache": "self.version",
"drupal/editor": "self.version",
"drupal/entity_reference": "self.version",
"drupal/field": "self.version",
......
......@@ -250,17 +250,20 @@ services:
class: Drupal\Core\PageCache\ResponsePolicy\KillSwitch
tags:
- { name: page_cache_response_policy }
- { name: dynamic_page_cache_response_policy }
page_cache_no_cache_routes:
class: Drupal\Core\PageCache\ResponsePolicy\DenyNoCacheRoutes
arguments: ['@current_route_match']
public: false
tags:
- { name: page_cache_response_policy }
- { name: dynamic_page_cache_response_policy }
page_cache_no_server_error:
class: Drupal\Core\PageCache\ResponsePolicy\NoServerError
public: false
tags:
- { name: page_cache_response_policy }
- { name: dynamic_page_cache_response_policy }
config.manager:
class: Drupal\Core\Config\ConfigManager
arguments: ['@entity.manager', '@config.factory', '@config.typed', '@string_translation', '@config.storage', '@event_dispatcher']
......
......@@ -40,7 +40,7 @@ public function onRequestDeriveFormWrapper(GetResponseEvent $event) {
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onRequestDeriveFormWrapper', 29);
$events[KernelEvents::REQUEST][] = array('onRequestDeriveFormWrapper', 25);
return $events;
}
......
name: Internal Dynamic Page Cache
type: module
description: 'Caches pages for any user, handling dynamic content correctly.'
package: Core
version: VERSION
core: 8.x
<?php
/**
* @file
* Caches HTML responses, request and response policies allowing.
*/
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function dynamic_page_cache_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.dynamic_page_cache':
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Dynamic Page Cache module caches pages for all users in the database, handling dynamic content correctly. For more information, see the <a href="!dynamic_page_cache-documentation">online documentation for the Dynamic Page Cache module</a>.', ['!dynamic_page_cache-documentation' => 'https://www.drupal.org/documentation/modules/dynamic_page_cache']) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Speeding up your site') . '</dt>';
$output .= '<dd>' . t('Pages are cached the first time they are requested if they are suitable from caching, then the cached version is served for all later requests. Dynamic content is handled automatically so that both cache correctness and hit ratio is maintained.') . '</dd>';
$output .= '<dd>' . t('The module requires no configuration. Every part of the page contains metadata that allows Dynamic Page Cache to figure this out on its own.') . '</dd>';
$output .= '</dl>';
return $output;
}
}
services:
cache.dynamic_page_cache:
class: Drupal\Core\Cache\CacheBackendInterface
tags:
- { name: cache.bin }
factory: cache_factory:get
arguments: [dynamic_page_cache]
dynamic_page_cache_subscriber:
class: Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber
arguments: ['@dynamic_page_cache_request_policy', '@dynamic_page_cache_response_policy', '@render_cache', '%renderer.config%']
tags:
- { name: event_subscriber }
# Request & response policies.
dynamic_page_cache_request_policy:
class: Drupal\dynamic_page_cache\PageCache\RequestPolicy\DefaultRequestPolicy
tags:
- { name: service_collector, tag: dynamic_page_cache_request_policy, call: addPolicy}
dynamic_page_cache_response_policy:
class: Drupal\Core\PageCache\ChainResponsePolicy
tags:
- { name: service_collector, tag: dynamic_page_cache_response_policy, call: addPolicy}
lazy: true
dynamic_page_cache_deny_admin_routes:
class: Drupal\dynamic_page_cache\PageCache\ResponsePolicy\DenyAdminRoutes
arguments: ['@current_route_match']
public: false
tags:
- { name: dynamic_page_cache_response_policy }
<?php
/**
* @file
* Contains \Drupal\dynamic_page_cache\PageCache\RequestPolicy\DefaultRequestPolicy.
*/
namespace Drupal\dynamic_page_cache\PageCache\RequestPolicy;
use Drupal\Core\PageCache\ChainRequestPolicy;
use Drupal\Core\PageCache\RequestPolicy\CommandLineOrUnsafeMethod;
/**
* The default Dynamic Page Cache request policy.
*
* Delivery of cached pages is denied if either the application is running from
* the command line or the request was not initiated with a safe method (GET or
* HEAD).
*/
class DefaultRequestPolicy extends ChainRequestPolicy {
/**
* Constructs the default Dynamic Page Cache request policy.
*/
public function __construct() {
$this->addPolicy(new CommandLineOrUnsafeMethod());
}
}
<?php
/**
* @file
* Contains \Drupal\dynamic_page_cache\PageCache\ResponsePolicy\DenyAdminRoutes.
*/
namespace Drupal\dynamic_page_cache\PageCache\ResponsePolicy;
use Drupal\Core\PageCache\ResponsePolicyInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Cache policy for routes with the '_admin_route' option set.
*
* This policy rule denies caching of responses generated for admin routes,
* because admin routes have very low cache hit ratios due to low traffic and
* form submissions.
*/
class DenyAdminRoutes implements ResponsePolicyInterface {
/**
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Constructs a deny admin route 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 (($route = $this->routeMatch->getRouteObject()) && $route->getOption('_admin_route')) {
return static::DENY;
}
}
}
<?php
/**
* @file
* Contains \Drupal\dynamic_page_cache\Tests\DynamicPageCacheIntegrationTest.
*/
namespace Drupal\dynamic_page_cache\Tests;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Url;
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
use Drupal\simpletest\WebTestBase;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Enables the Dynamic Page Cache and tests it in various scenarios.
*
* This does not test the self-healing of the redirect with conditional cache
* contexts, because Dynamic Page Cache just reuses
* \Drupal\Core\Render\RenderCache so that it doesn't have to implement and test
* all of that again. It is tested in
* RendererBubblingTest::testConditionalCacheContextBubblingSelfHealing().
*
* @group dynamic_page_cache
*
* @see \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber
*/
class DynamicPageCacheIntegrationTest extends WebTestBase {
/**
* {@inheritdoc}
*/
protected $dumpHeaders = TRUE;
/**
* {@inheritdoc}
*/
protected static $modules = ['dynamic_page_cache_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Uninstall the page_cache module; we want to test the Dynamic Page Cache
// alone.
\Drupal::service('module_installer')->uninstall(['page_cache']);
}
/**
* Tests that Dynamic Page Cache works correctly, and verifies the edge cases.
*/
public function testDynamicPageCache() {
// Controllers returning plain response objects are ignored by Dynamic Page
// Cache.
$url = Url::fromUri('route:dynamic_page_cache_test.response');
$this->drupalGet($url);
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Response object returned: Dynamic Page Cache is ignoring.');
// Controllers returning CacheableResponseInterface (cacheable response)
// objects are handled by Dynamic Page Cache.
$url = Url::fromUri('route:dynamic_page_cache_test.cacheable_response');
$this->drupalGet($url);
$this->assertEqual('MISS', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Cacheable response object returned: Dynamic Page Cache is active, Dynamic Page Cache MISS.');
$this->drupalGet($url);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Cacheable response object returned: Dynamic Page Cache is active, Dynamic Page Cache HIT.');
// Controllers returning render arrays, rendered as HTML responses, are
// handled by Dynamic Page Cache.
$url = Url::fromUri('route:dynamic_page_cache_test.html');
$this->drupalGet($url);
$this->assertEqual('MISS', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response: Dynamic Page Cache is active, Dynamic Page Cache MISS.');
$this->drupalGet($url);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response: Dynamic Page Cache is active, Dynamic Page Cache HIT.');
// The above is the simple case, where the render array returned by the
// response contains no cache contexts. So let's now test a route/controller
// that *does* vary by a cache context whose value we can easily control: it
// varies by the 'animal' query argument.
foreach (['llama', 'piggy', 'unicorn', 'kitten'] as $animal) {
$url = Url::fromUri('route:dynamic_page_cache_test.html.with_cache_contexts', ['query' => ['animal' => $animal]]);
$this->drupalGet($url);
$this->assertRaw($animal);
$this->assertEqual('MISS', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response: Dynamic Page Cache is active, Dynamic Page Cache MISS.');
$this->drupalGet($url);
$this->assertRaw($animal);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response: Dynamic Page Cache is active, Dynamic Page Cache HIT.');
// Finally, let's also verify that the 'dynamic_page_cache_test.html'
// route continued to see cache hits if we specify a query argument,
// because it *should* ignore it and continue to provide Dynamic Page
// Cache hits.
$url = Url::fromUri('route:dynamic_page_cache_test.html', ['query' => ['animal' => 'piglet']]);
$this->drupalGet($url);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response: Dynamic Page Cache is active, Dynamic Page Cache HIT.');
}
// Controllers returning render arrays, rendered as anything except a HTML
// response, are ignored by Dynamic Page Cache (but only because those
// wrapper formats' responses do not implement CacheableResponseInterface).
$this->drupalGet('dynamic-page-cache-test/html', array('query' => array(MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax')));
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as AJAX response: Dynamic Page Cache is ignoring.');
$this->drupalGet('dynamic-page-cache-test/html', array('query' => array(MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog')));
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as dialog response: Dynamic Page Cache is ignoring.');
$this->drupalGet('dynamic-page-cache-test/html', array('query' => array(MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal')));
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as modal response: Dynamic Page Cache is ignoring.');
// Admin routes are ignored by Dynamic Page Cache.
$this->drupalGet('dynamic-page-cache-test/html/admin');
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Response returned, rendered as HTML response, admin route: Dynamic Page Cache is ignoring');
$this->drupalGet('dynamic-page-cache-test/response/admin');
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Response returned, plain response, admin route: Dynamic Page Cache is ignoring');
$this->drupalGet('dynamic-page-cache-test/cacheable-response/admin');
$this->assertFalse($this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Response returned, cacheable response, admin route: Dynamic Page Cache is ignoring');
// Max-age = 0 responses are ignored by Dynamic Page Cache.
$this->drupalGet('dynamic-page-cache-test/html/uncacheable/max-age');
$this->assertEqual('UNCACHEABLE', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response, but uncacheable: Dynamic Page Cache is running, but not caching.');
// 'user' cache context responses are ignored by Dynamic Page Cache.
$this->drupalGet('dynamic-page-cache-test/html/uncacheable/contexts');
$this->assertEqual('UNCACHEABLE', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Render array returned, rendered as HTML response, but uncacheable: Dynamic Page Cache is running, but not caching.');
// 'current-temperature' cache tag responses are ignored by Dynamic Page
// Cache.
$this->drupalGet('dynamic-page-cache-test/html/uncacheable/tags');
$this->assertEqual('MISS', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'By default, Drupal has no auto-placeholdering cache tags.');
}
}
name: 'Test Dynamic Page Cache'
type: module
description: 'Provides test routes/responses for Dynamic Page Cache.'
package: Testing
version: VERSION
core: 8.x
dynamic_page_cache_test.response:
path: '/dynamic-page-cache-test/response'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::response'
requirements:
_access: 'TRUE'
dynamic_page_cache_test.response.admin:
path: '/dynamic-page-cache-test/response/admin'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::response'
requirements:
_access: 'TRUE'
options:
_admin_route: TRUE
dynamic_page_cache_test.cacheable_response:
path: '/dynamic-page-cache-test/cacheable-response'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::cacheableResponse'
requirements:
_access: 'TRUE'
dynamic_page_cache_test.cacheable_response.admin:
path: '/dynamic-page-cache-test/cacheable-response/admin'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::cacheableResponse'
requirements:
_access: 'TRUE'
options:
_admin_route: TRUE
dynamic_page_cache_test.html:
path: '/dynamic-page-cache-test/html'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::html'
requirements:
_access: 'TRUE'
dynamic_page_cache_test.html.admin:
path: '/dynamic-page-cache-test/html/admin'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::html'
requirements:
_access: 'TRUE'
options:
_admin_route: TRUE
dynamic_page_cache_test.html.with_cache_contexts:
path: '/dynamic-page-cache-test/html/with-cache-contexts'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::htmlWithCacheContexts'
requirements:
_access: 'TRUE'
dynamic_page_cache_test.html.uncacheable.max_age:
path: '/dynamic-page-cache-test/html/uncacheable/max-age'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::htmlUncacheableMaxAge'
requirements:
_access: 'TRUE'
dynamic_page_cache_test.html.uncacheable.contexts:
path: '/dynamic-page-cache-test/html/uncacheable/contexts'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::htmlUncacheableContexts'
requirements:
_access: 'TRUE'
dynamic_page_cache_test.html.uncacheable.tags:
path: '/dynamic-page-cache-test/html/uncacheable/tags'
defaults:
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::htmlUncacheableTags'
requirements:
_access: 'TRUE'
<?php
/**
* @file
* Contains \Drupal\dynamic_page_cache_test\DynamicPageCacheTestController.
*/
namespace Drupal\dynamic_page_cache_test;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Cache\CacheableResponse;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\Response;
/**
* Controller routines for dynamic_page_cache_test routes.
*/
class DynamicPageCacheTestController {
/**
* A route returning a Response object.
*
* @return \Symfony\Component\HttpFoundation\Response
* A Response object.
*/
public function response() {
return new Response('foobar');
}
/**
* A route returning a CacheableResponse object.
*
* @return \Drupal\Core\Cache\CacheableResponseInterface
* A CacheableResponseInterface object.
*/
public function cacheableResponse() {
$user = User::load(1);
$response = new CacheableResponse($user->label());
$response->addCacheableDependency($user);
return $response;
}
/**
* A route returning a render array (without cache contexts, so cacheable).
*
* @return array
* A render array.
*/
public function html() {
return [
'content' => [
'#markup' => 'Hello world.',
],
];
}
/**
* A route returning a render array (with cache contexts, so cacheable).
*
* @return array
* A render array.
*
* @see html()
*/
public function htmlWithCacheContexts() {
$build = $this->html();
$build['dynamic_part'] = [
'#markup' => SafeMarkup::format('Hello there, %animal.', ['%animal' => \Drupal::requestStack()->getCurrentRequest()->query->get('animal')]),
'#cache' => [
'contexts' => [
'url.query_args:animal',
],
],
];
return $build;
}
/**
* A route returning a render array (with max-age=0, so uncacheable)
*
* @return array
* A render array.
*
* @see html()
*/
public function htmlUncacheableMaxAge() {
$build = $this->html();
$build['very_dynamic_part'] = [
'#markup' => 'Drupal cannot handle the awesomeness of llamas.',
'#cache' => [
'max-age' => 0,
],
];
return $build;
}
/**
* A route returning a render array (with 'user' context, so uncacheable)
*
* @return array
* A render array.
*
* @see html()
*/
public function htmlUncacheableContexts() {
$build = $this->html();
$build['very_dynamic_part'] = [
'#markup' => 'Drupal cannot handle the awesomeness of llamas.',
'#cache' => [
'contexts' => [
'user',
],
],
];
return $build;
}
/**
* A route returning a render array (with max-age=0, so uncacheable)
*
* @return array
* A render array.
*
* @see html()
*/
public function htmlUncacheableTags() {
$build = $this->html();
$build['very_dynamic_part'] = [
'#markup' => 'Drupal cannot handle the awesomeness of llamas.',
'#cache' => [
'tags' => [
'current-temperature',
],
],
];
return $build;
}
}
name: Internal Page Cache
type: module
description: 'Caches pages for anonymous users. Works well for small to medium-sized websites.'
description: 'Caches pages for anonymous users. Use when an external page cache is not available.'
package: Core
version: VERSION
core: 8.x
......@@ -5,9 +5,8 @@
* Caches responses for anonymous users, request and response policies allowing.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\PageCache\RequestPolicyInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
/**
* Implements hook_help().
......@@ -21,7 +20,8 @@ function page_cache_help($route_name, RouteMatchInterface $route_match) {
$output .= '<dl>';
$output .= '<dt>' . t('Speeding up your site') . '</dt>';
$output .= '<dd>' . t('Pages requested by anonymous users are stored the first time they are requested and then are reused. Depending on your site configuration and the amount of your web traffic tied to anonymous visitors, the caching system may significantly increase the speed of your site.') . '</dd>';
$output .= '<dd>' . t('Pages are usually identical for all anonymous users, while they can be customized for each authenticated user. This is why pages can be cached for anonymous users, whereas they will have to be rebuilt for every authenticated user.') . '</dd>';
$output .= '<dd>' . t('Pages are usually identical for all anonymous users, while they can be personalized for each authenticated user. This is why entire pages can be cached for anonymous users, whereas they will have to be rebuilt for every authenticated user.') . '</dd>';
$output .= '<dd>' . t('To speed up your site for authenticated users, see the <a href="!dynamic_page_cache-help">Dynamic Page Cache module</a>.', ['!dynamic_page_cache-help' => (\Drupal::moduleHandler()->moduleExists('dynamic_page_cache')) ? Url::fromRoute('help.page', ['name' => 'dynamic_page_cache'])->toString() : '#']) . '</p>';
$output .= '<dt>' . t('Configuring the internal page cache') . '</dt>';
$output .= '<dd>' . t('On the <a href="!cache-settings">Performance page</a>, you can configure how long browsers and proxies may cache pages; that setting is also respected by the Internal Page Cache module. There is no other configuration.', array('!cache-settings' => \Drupal::url('system.performance_settings'))) . '</dd>';
$output .= '</dl>';
......
......@@ -61,7 +61,7 @@ public function onSave(ConfigCrudEvent $event) {
}
// Theme configuration and global theme settings.
if (in_array($event->getConfig()->getName(), ['system.theme', 'system.theme.global'])) {
if (in_array($event->getConfig()->getName(), ['system.theme', 'system.theme.global'], TRUE)) {
$this->cacheTagsInvalidator->invalidateTags(['rendered']);
}
......
......@@ -153,6 +153,11 @@ public function testSessionPersistenceOnLogin() {
* Test that empty anonymous sessions are destroyed.
*/
function testEmptyAnonymousSession() {
// Disable the dynamic_page_cache module; it'd cause session_test's debug
// output (that is added in
// SessionTestSubscriber::onKernelResponseSessionTest()) to not be added.
$this->container->get('module_installer')->uninstall(['dynamic_page_cache']);
// Verify that no session is automatically created for anonymous user when
// page caching is disabled.
$this->container->get('module_installer')->uninstall(['page_cache']);
......
......@@ -90,7 +90,7 @@ function system_help($route_name, RouteMatchInterface $route_match) {
$output .= '<dt>' . t('Using maintenance mode') . '</dt>';
$output .= '<dd>' . t('When you are performing site maintenance, you can prevent non-administrative users (including anonymous visitors) from viewing your site by putting it in <a href="!maintenance-mode">Maintenance mode</a>. This will prevent unauthorized users from making changes to the site while you are performing maintenance, or from seeing a broken site while updates are in progress.', array('!maintenance-mode' => \Drupal::url('system.site_maintenance_mode'))) . '</dd>';
$output .= '<dt>' . t('Configuring for performance') . '</dt>';
$output .= '<dd>' . t('On the <a href="!performance-page">Performance page</a>, the site can be configured to aggregate CSS and JavaScript files, making the total request size smaller. Note that, for small- to medium-sized websites, the <a href="!page-cache">Internal Page Cache module</a> should be installed so that pages are efficiently cached and reused.', array('!performance-page' => \Drupal::url('system.performance_settings'), '!page-cache' => (\Drupal::moduleHandler()->moduleExists('page_cache')) ? \Drupal::url('help.page', array('name' => 'page_cache')) : '#')) . '</dd>';
$output .= '<dd>' . t('On the <a href="!performance-page">Performance page</a>, the site can be configured to aggregate CSS and JavaScript files, making the total request size smaller. Note that, for small- to medium-sized websites, the <a href="!page-cache">Internal Page Cache module</a> should be installed so that pages are efficiently cached and reused for anonymous users. Finally, for websites of all sizes, the <a href="!dynamic-page-cache">Dynamic Page Cache module</a> should also be installed so that the non-personalized parts of pages are efficiently cached (for all users).', array('!performance-page' => \Drupal::url('system.performance_settings'), '!page-cache' => (\Drupal::moduleHandler()->moduleExists('page_cache')) ? \Drupal::url('help.page', array('name' => 'page_cache')) : '#', '!dynamic-page-cache' => (\Drupal::moduleHandler()->moduleExists('dynamic_page_cache')) ? \Drupal::url('help.page', array('name' => 'dynamic_page_cache')) : '#')) . '</dd>';
$output .= '<dt>' . t('Configuring cron') . '</dt>';
$output .= '<dd>' . t('In order for the site and its modules to continue to operate well, a set of routine administrative operations must run on a regular basis; these operations are known as <em>cron</em> tasks. On the <a href="!cron">Cron page</a>, you can configure cron to run periodically as part of normal page requests, or you can turn this off and trigger cron from an outside process on your web server. You can verify the status of cron tasks by visiting the <a href="!status">Status report page</a>. For more information, see the <a href="!handbook">online documentation for configuring cron jobs</a>.', array('!status' => \Drupal::url('system.status'), '!handbook' => 'https://www.drupal.org/cron', '!cron' => \Drupal::url('system.cron_settings'))) . '</dd>';
$output .= '<dt>' . t('Configuring the file system') . '</dt>';
......
......@@ -8,5 +8,6 @@ dependencies:
- block
- dblog
- page_cache
- dynamic_page_cache
themes:
- stark
......@@ -9,6 +9,8 @@
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\contact\Entity\ContactForm;
use Drupal\Core\Url;
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
use Drupal\filter\Entity\FilterFormat;
use Drupal\simpletest\WebTestBase;
use Drupal\user\Entity\Role;
......@@ -177,5 +179,28 @@ function testStandard() {
$this->assertText('Max 650x650');
$this->assertText('Max 1300x1300');
$this->assertText('Max 2600x2600');
// Verify certain routes' responses are cacheable by Dynamic Page Cache, to
// ensure these responses are very fast for authenticated users.
$this->dumpHeaders = TRUE;
$this->drupalLogin($this->adminUser);
$url = Url::fromRoute('contact.site_page');
$this->drupalGet($url);
$this->assertEqual('UNCACHEABLE', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Site-wide contact page cannot be cached by Dynamic Page Cache.');
$url = Url::fromRoute('<front>');
$this->drupalGet($url);
$this->drupalGet($url);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Frontpage is cached by Dynamic Page Cache.');
$url = Url::fromRoute('entity.node.canonical', ['node' => 1]);
$this->drupalGet($url);
$this->drupalGet($url);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'Full node page is cached by Dynamic Page Cache.');
$url = Url::fromRoute('entity.user.canonical', ['user' => 1]);
$this->drupalGet($url);
$this->drupalGet($url);
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER), 'User profile page is cached by Dynamic Page Cache.');
}
}
......@@ -26,6 +26,7 @@ dependencies:
- options
- path
- page_cache
- dynamic_page_cache
- taxonomy
- dblog
- search
......