Issue #2368987 by Wim Leers, Berdir, Schnitzel, epari.siva, bircher, vijaycs85, likin: Move internal page caching to a module to avoid relying on config get on runtime

8.0.x
Nathaniel Catchpole 2015-04-17 11:54:56 +01:00
parent d4431a10d7
commit b986c827fb
39 changed files with 201 additions and 370 deletions

View File

@ -300,7 +300,7 @@ services:
arguments: ['@request_stack', '@url_generator']
form_cache:
class: Drupal\Core\Form\FormCache
arguments: ['@app.root', '@keyvalue.expirable', '@module_handler', '@current_user', '@csrf_token', '@logger.channel.form', '@config.factory', '@request_stack', '@page_cache_request_policy']
arguments: ['@app.root', '@keyvalue.expirable', '@module_handler', '@current_user', '@csrf_token', '@logger.channel.form', '@request_stack', '@page_cache_request_policy']
public: false # Private to form_builder
keyvalue:
class: Drupal\Core\KeyValueStore\KeyValueFactory
@ -584,11 +584,6 @@ services:
arguments: ['@settings']
tags:
- { name: http_middleware, priority: 300 }
http_middleware.page_cache:
class: Drupal\Core\StackMiddleware\PageCache
arguments: ['@cache.render', '@page_cache_request_policy', '@page_cache_response_policy']
tags:
- { name: http_middleware, priority: 200 }
http_middleware.kernel_pre_handle:
class: Drupal\Core\StackMiddleware\KernelPreHandle
arguments: ['@kernel']

View File

@ -10,7 +10,6 @@ namespace Drupal\Core\Form;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Drupal\Core\PageCache\RequestPolicyInterface;
@ -104,20 +103,17 @@ class FormCache implements FormCacheInterface {
* The CSRF token generator.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\Core\PageCache\RequestPolicyInterface $request_policy
* A policy rule determining the cacheability of a request.
*/
public function __construct($root, KeyValueExpirableFactoryInterface $key_value_expirable_factory, ModuleHandlerInterface $module_handler, AccountInterface $current_user, CsrfTokenGenerator $csrf_token, LoggerInterface $logger, ConfigFactoryInterface $config_factory, RequestStack $request_stack, RequestPolicyInterface $request_policy) {
public function __construct($root, KeyValueExpirableFactoryInterface $key_value_expirable_factory, ModuleHandlerInterface $module_handler, AccountInterface $current_user, CsrfTokenGenerator $csrf_token, LoggerInterface $logger, RequestStack $request_stack, RequestPolicyInterface $request_policy) {
$this->root = $root;
$this->keyValueExpirableFactory = $key_value_expirable_factory;
$this->moduleHandler = $module_handler;
$this->currentUser = $current_user;
$this->logger = $logger;
$this->configFactory = $config_factory;
$this->csrfToken = $csrf_token;
$this->requestStack = $request_stack;
$this->requestPolicy = $request_policy;
@ -210,11 +206,6 @@ class FormCache implements FormCacheInterface {
$this->keyValueExpirableFactory->get('form')->setWithExpire($form_build_id, $form, $expire);
}
// Cache form state.
if ($this->configFactory->get('system.performance')->get('cache.page.use_internal') && $this->isPageCacheable()) {
$form_state->addBuildInfo('immutable', TRUE);
}
// Store the known list of safe strings for form re-use.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
@ -225,14 +216,4 @@ class FormCache implements FormCacheInterface {
}
}
/**
* Checks if the page is cacheable.
*
* @return bool
* TRUE is the page is cacheable, FALSE if not.
*/
protected function isPageCacheable() {
return ($this->requestPolicy->check($this->requestStack->getCurrentRequest()) === RequestPolicyInterface::ALLOW);
}
}

View File

@ -32,7 +32,6 @@ class BasicAuthTest extends WebTestBase {
public function testBasicAuth() {
// Enable page caching.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();

View File

@ -313,7 +313,6 @@ class BlockTest extends BlockTestBase {
// Enable page caching.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();

View File

@ -51,19 +51,6 @@ class DownloadTest extends FileManagedTestBase {
$this->doPrivateFileTransferTest();
}
/**
* Test the private file transfer system with page cache.
*/
public function testPrivateFileTransferWithPageCache() {
// Turn on page caching and rerun the test.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
$this->doPrivateFileTransferTest();
}
/**
* Test the private file transfer system.
*/

View File

@ -78,22 +78,6 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
$this->doImageStyleUrlAndPathTests('private', FALSE);
}
/**
* Tests an image style URL using the "public://" scheme and page cache.
*/
public function testImageStyleUrlAndPathPublicWithPageCache() {
$this->enablePageCache();
$this->doImageStyleUrlAndPathTests('public');
}
/**
* Tests an image style URL using the "private://" scheme and page cache.
*/
public function testImageStyleUrlAndPathPrivateWithPageCache() {
$this->enablePageCache();
$this->doImageStyleUrlAndPathTests('private');
}
/**
* Tests an image style URL with a file URL that has an extra slash in it.
*/
@ -242,15 +226,4 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
$this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
}
/**
* Turn on page caching.
*/
protected function enablePageCache() {
// Turn on page caching and rerun the test.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
}
}

View File

@ -188,20 +188,7 @@ class LanguageNegotiator implements LanguageNegotiatorInterface {
$method = $this->negotiatorManager->getDefinition($method_id);
if (!isset($method['types']) || in_array($type, $method['types'])) {
// Check for a cache mode force from settings.php.
if ($this->settings->get('page_cache_without_database')) {
$cache_enabled = TRUE;
}
else {
$cache_enabled = $this->configFactory->get('system.performance')->get('cache.page.use_internal');
}
// If the language negotiation method has no cache preference or this is
// satisfied we can execute the callback.
if ($cache = !isset($method['cache']) || $this->currentUser->isAuthenticated() || $method['cache'] == $cache_enabled) {
$langcode = $this->getNegotiationMethodInstance($method_id)->getLangcode($this->requestStack->getCurrentRequest());
}
$langcode = $this->getNegotiationMethodInstance($method_id)->getLangcode($this->requestStack->getCurrentRequest());
}
$languages = $this->languageManager->getLanguages();

View File

@ -35,16 +35,16 @@ class LanguageNegotiationBrowser extends LanguageNegotiationMethodBase {
public function getLangcode(Request $request = NULL) {
$langcode = NULL;
// Whenever browser-based language negotiation is used, the page cannot be
// cached by reverse proxies.
// @todo Solve more elegantly in https://www.drupal.org/node/2430335.
\Drupal::service('page_cache_kill_switch')->trigger();
if ($this->languageManager && $request && $request->server->get('HTTP_ACCEPT_LANGUAGE')) {
$http_accept_language = $request->server->get('HTTP_ACCEPT_LANGUAGE');
$langcodes = array_keys($this->languageManager->getLanguages());
$mappings = $this->config->get('language.mappings')->get('map');
$langcode = UserAgent::getBestMatchingLangcode($http_accept_language, $langcodes, $mappings);
// Internal page cache with multiple languages and browser negotiation
// could lead to wrong cached sites. Therefore disabling the internal
// page cache.
// @todo Solve more elegantly in https://www.drupal.org/node/2430335.
\Drupal::service('page_cache_kill_switch')->trigger();
}
return $langcode;

View File

@ -14,7 +14,6 @@ process:
'css/preprocess': preprocess_css
'js/preprocess': preprocess_js
'cache/page/max_age': cache_lifetime
'cache/page/use_internal': cache
'response/gzip': page_compression
destination:
plugin: config

View File

@ -40,8 +40,6 @@ class MigrateSystemPerformanceTest extends MigrateDrupal6TestBase {
$this->assertIdentical(FALSE, $config->get('css.preprocess'));
$this->assertIdentical(FALSE, $config->get('js.preprocess'));
$this->assertIdentical(0, $config->get('cache.page.max_age'));
$this->assertIdentical(TRUE, $config->get('cache.page.use_internal'));
$this->assertIdentical(TRUE, $config->get('response.gzip'));
}
}

View File

@ -0,0 +1,6 @@
name: Internal page cache
type: module
description: 'Caches pages for anonymous users. Works well for small to medium-sized websites.'
package: Core
version: VERSION
core: 8.x

View File

@ -0,0 +1,50 @@
<?php
/**
* @file
* 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;
/**
* Implements hook_help().
*/
function page_cache_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.page_cache':
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Internal page cache module caches pages for anonymous users in the database.') . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Speeding up your site') . '</dt>';
$output .= '<dd>';
$output .= '<p>' . t('Pages requested by anonymous users are stored the first time they are requested and then 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.');
$output .= '<p>' . t('(For authenticated users, pages need to be assembled for each user individually, but anonymous users all get the exact same version of each page.)') . '</p>';
$output .= '</dd>';
$output .= '<dt>' . t('Configuring Internal page cache') . '</dt>';
$output .= '<dd>';
$output .= '<p>' . t('On the <a href="@cache-settings">Performance settings 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'))) . '</p>';
$output .= '</dd>';
$output .= '</dl>';
return $output;
}
}
/**
* Implements hook_form_alter().
*/
function page_cache_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// If the page that's being built is cacheable, set the 'immutable' flag, to
// ensure that when the form is used, a new form build ID is generated when
// appropriate, to prevent information disclosure.
$request_policy = \Drupal::service('page_cache_request_policy');
$request = \Drupal::requestStack()->getCurrentRequest();
$request_is_cacheable = $request_policy->check($request) === RequestPolicyInterface::ALLOW;
if ($request_is_cacheable) {
$form_state->addBuildInfo('immutable', TRUE);
}
}

View File

@ -0,0 +1,6 @@
services:
http_middleware.page_cache:
class: Drupal\page_cache\StackMiddleware\PageCache
arguments: ['@cache.render', '@page_cache_request_policy', '@page_cache_response_policy']
tags:
- { name: http_middleware, priority: 200 }

View File

@ -2,11 +2,12 @@
/**
* @file
* Contains \Drupal\Core\StackMiddleware\PageCache.
* Contains \Drupal\page_cache\StackMiddleware\PageCache.
*/
namespace Drupal\Core\StackMiddleware;
namespace Drupal\page_cache\StackMiddleware;
use Drupal\Component\Utility\UserAgent;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\PageCache\RequestPolicyInterface;
@ -52,7 +53,7 @@ class PageCache implements HttpKernelInterface {
protected $responsePolicy;
/**
* Constructs a ReverseProxyMiddleware object.
* Constructs a PageCache object.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
* The decorated kernel.
@ -74,20 +75,8 @@ class PageCache implements HttpKernelInterface {
* {@inheritdoc}
*/
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
if ($type !== static::MASTER_REQUEST) {
// Only allow page caching on master request.
$cache_enabled = FALSE;
}
elseif (Settings::get('page_cache_without_database')) {
// Check for a cache mode force from settings.php.
$cache_enabled = TRUE;
}
else {
$config = $this->config('system.performance');
$cache_enabled = $config->get('cache.page.use_internal');
}
if ($cache_enabled && $this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW) {
// Only allow page caching on master request.
if ($type === static::MASTER_REQUEST && $this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW) {
$response = $this->lookup($request, $type, $catch);
}
else {
@ -232,20 +221,6 @@ class PageCache implements HttpKernelInterface {
return $response;
}
// Check if the current page may be compressed.
if (extension_loaded('zlib') && !$response->headers->get('Content-Encoding') && $this->config('system.performance')->get('response.gzip')) {
$content = $response->getContent();
if ($content) {
$response->setContent(gzencode($content, 9, FORCE_GZIP));
$response->headers->set('Content-Encoding', 'gzip');
}
// When page compression is enabled, ensure that proxy caches will record
// and deliver different versions of a page depending on whether the
// client supports gzip or not.
$response->setVary('Accept-Encoding', FALSE);
}
// Use the actual timestamp from an Expires header, if available.
$date = $response->getExpires();
$expire = ($date > (new \DateTime())) ? $date->getTimestamp() : Cache::PERMANENT;
@ -326,16 +301,4 @@ class PageCache implements HttpKernelInterface {
return implode(':', $cid_parts);
}
/**
* Wraps Drupal::config().
*
* Config factory is not injected into this class in order to prevent
* premature initialization of config storage (database).
*
* @see \Drupal::config()
*/
protected function config($name) {
return \Drupal::config($name);
}
}

View File

@ -2,19 +2,20 @@
/**
* @file
* Contains \Drupal\system\Tests\Cache\PageCacheTagsIntegrationTest.
* Contains \Drupal\page_cache\Tests\PageCacheTagsIntegrationTest.
*/
namespace Drupal\system\Tests\Cache;
namespace Drupal\page_cache\Tests;
use Drupal\Core\Language\LanguageInterface;
use Drupal\simpletest\WebTestBase;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Enables the page cache and tests its cache tags in various scenarios.
*
* @group Cache
* @see \Drupal\system\Tests\Bootstrap\PageCacheTest
* @see \Drupal\page_cache\Tests\PageCacheTest
* @see \Drupal\node\Tests\NodePageCacheTest
* @see \Drupal\menu_ui\Tests\MenuTest::testMenuBlockPageCacheTags()
*/

View File

@ -2,13 +2,12 @@
/**
* @file
* Definition of Drupal\system\Tests\Bootstrap\PageCacheTest.
* Contains \Drupal\page_cache\Tests\PageCacheTest.
*/
namespace Drupal\system\Tests\Bootstrap;
namespace Drupal\page_cache\Tests;
use Drupal\Component\Datetime\DateTimePlus;
use Drupal\Core\Routing\RequestContext;
use Drupal\Core\Url;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\simpletest\WebTestBase;
@ -19,7 +18,7 @@ use Drupal\user\RoleInterface;
/**
* Enables the page cache and tests it with various HTTP requests.
*
* @group Bootstrap
* @group page_cache
*/
class PageCacheTest extends WebTestBase {
@ -32,6 +31,9 @@ class PageCacheTest extends WebTestBase {
*/
public static $modules = array('test_page_test', 'system_test', 'entity_test');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
@ -49,7 +51,6 @@ class PageCacheTest extends WebTestBase {
*/
function testPageCacheTags() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
@ -82,24 +83,21 @@ class PageCacheTest extends WebTestBase {
*/
function testAcceptHeaderRequests() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
$url_generator = \Drupal::urlGenerator();
$url_generator->setContext(new RequestContext());
$accept_header_cache_uri = $url_generator->getPathFromRoute('system_test.page_cache_accept_header');
$accept_header_cache_url = Url::fromRoute('system_test.page_cache_accept_header');
$json_accept_header = array('Accept: application/json');
$this->drupalGet($accept_header_cache_uri);
$this->drupalGet($accept_header_cache_url);
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'HTML page was not yet cached.');
$this->drupalGet($accept_header_cache_uri);
$this->drupalGet($accept_header_cache_url);
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'HTML page was cached.');
$this->assertRaw('<p>oh hai this is html.</p>', 'The correct HTML response was returned.');
$this->drupalGet($accept_header_cache_uri, array(), $json_accept_header);
$this->drupalGet($accept_header_cache_url, array(), $json_accept_header);
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Json response was not yet cached.');
$this->drupalGet($accept_header_cache_uri, array(), $json_accept_header);
$this->drupalGet($accept_header_cache_url, array(), $json_accept_header);
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Json response was cached.');
$this->assertRaw('{"content":"oh hai this is json"}', 'The correct Json response was returned.');
@ -153,7 +151,6 @@ class PageCacheTest extends WebTestBase {
*/
function testConditionalRequests() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
@ -198,7 +195,6 @@ class PageCacheTest extends WebTestBase {
*/
function testPageCache() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->set('response.gzip', 1);
$config->save();
@ -258,9 +254,8 @@ class PageCacheTest extends WebTestBase {
* This test verifies that, and it verifies that it does not happen for other
* roles.
*/
function testPageCacheAnonymousRolePermissions() {
public function testPageCacheAnonymousRolePermissions() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
@ -359,7 +354,6 @@ class PageCacheTest extends WebTestBase {
*/
public function testPageCacheWithoutVaryCookie() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
@ -373,58 +367,33 @@ class PageCacheTest extends WebTestBase {
$this->drupalGet('');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
$this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
// Check cache.
$this->drupalGet('');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
$this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
}
/**
* Tests page compression.
*
* The test should pass even if zlib.output_compression is enabled in php.ini,
* .htaccess or similar, or if compression is done outside PHP, e.g. by the
* mod_deflate Apache module.
* Test the setting of forms to be immutable.
*/
function testPageCompression() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->set('response.gzip', 1);
$config->save();
public function testFormImmutability() {
// Install the module that provides the test form.
$this->container->get('module_installer')
->install(['page_cache_form_test']);
\Drupal::service('router.builder')->rebuild();
// Fill the cache and verify that output is compressed.
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
$this->setRawContent(gzinflate(substr($this->getRawContent(), 10, -8)));
$this->assertRaw('</html>', 'Page was gzip compressed.');
$this->drupalGet('page_cache_form_test_immutability');
// Verify that cached output is compressed.
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
$this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', 'A Content-Encoding header was sent.');
$this->setRawContent(gzinflate(substr($this->getRawContent(), 10, -8)));
$this->assertRaw('</html>', 'Page was gzip compressed.');
$this->assertText("Immutable: TRUE", "Form is immutable.");
// Verify that a client without compression support gets an uncompressed page.
$this->drupalGet('');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
$this->assertFalse($this->drupalGetHeader('Content-Encoding'), 'A Content-Encoding header was not sent.');
$this->assertTitle(t('Test page | @site-name', array('@site-name' => $this->config('system.site')->get('name'))), 'Site title matches.');
$this->assertRaw('</html>', 'Page was not compressed.');
// Uninstall the page_cache module, verify the flag is not set.
$this->container->get('module_installer')->uninstall(['page_cache']);
// Disable compression mode.
$config->set('response.gzip', 0);
$config->save();
$this->drupalGet('page_cache_form_test_immutability');
// Verify if cached page is still available for a client with compression support.
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
$this->setRawContent(gzinflate(substr($this->getRawContent(), 10, -8)));
$this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support enabled).');
// Verify if cached page is still available for a client without compression support.
$this->drupalGet('');
$this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support disabled).');
$this->assertText("Immutable: FALSE", "Form is not immutable,");
}
}

View File

@ -0,0 +1,6 @@
name: 'Page Cache Form Test'
type: module
description: 'Support module for the Page Cache module tests.'
core: 8.x
package: Testing
version: VERSION

View File

@ -0,0 +1,13 @@
<?php
/**
* @file
*
* Install hooks for page_cache_form_test.
*/
function page_cache_form_test_install() {
// Set an explicit module weight, to ensure that the form alter hook is
// always called after page_cache_form_alter().
module_set_weight('page_cache_form_test', 10);
}

View File

@ -0,0 +1,20 @@
<?php
/**
* @file
* Provides functionality for testing form caching.
*/
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_form_FORM_ID_alter().
*/
function page_cache_form_test_form_page_cache_form_test_alter(&$form, FormStateInterface $form_state, $form_id) {
if (isset($form_state->getBuildInfo()['immutable']) && $form_state->getBuildInfo()['immutable']) {
$form['#suffix'] = 'Immutable: TRUE';
}
else {
$form['#suffix'] = 'Immutable: FALSE';
}
}

View File

@ -0,0 +1,6 @@
page_cache_form_test.test_immutability:
path: '/page_cache_form_test_immutability'
defaults:
_form: '\Drupal\page_cache_form_test\Form\TestForm'
requirements:
_access: 'TRUE'

View File

@ -0,0 +1,35 @@
<?php
/**
* @file
* Contains \Drupal\page_cache_form_test\Form\TestForm.
*/
namespace Drupal\page_cache_form_test\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class TestForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'page_cache_form_test';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#prefix'] = '<p>Llamas are awesome, but kittens are pretty cool too!</p>';
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) { }
}

View File

@ -39,13 +39,6 @@ class SearchPageCacheTagsTest extends SearchTestBase {
protected function setUp() {
parent::setUp();
// Enable the page cache.
// @todo Remove in https://www.drupal.org/node/606840.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
// Create user.
$this->searchingUser = $this->drupalCreateUser(array('search content', 'access user profiles'));

View File

@ -1,6 +1,5 @@
cache:
page:
use_internal: false
max_age: 0
css:
preprocess: true
@ -13,6 +12,4 @@ fast_404:
js:
preprocess: true
gzip: true
response:
gzip: false
stale_file_threshold: 2592000

View File

@ -155,14 +155,11 @@ system.performance:
mapping:
page:
type: mapping
label: 'Page cache'
label: 'Page caching'
mapping:
use_internal:
type: boolean
label: 'Use internal page cache'
max_age:
type: integer
label: 'Max age of page cache'
label: 'Max age'
css:
type: mapping
label: 'CSS performance settings'

View File

@ -121,6 +121,7 @@ class PerformanceForm extends ConfigFormBase {
'#type' => 'details',
'#title' => t('Caching'),
'#open' => TRUE,
'#description' => $this->t('Note: Drupal provides an internal page cache module that is recommended for small to medium-sized websites.'),
);
// Identical options to the ones for block caching.
// @see \Drupal\Core\Block\BlockBase::buildConfigurationForm()
@ -132,14 +133,7 @@ class PerformanceForm extends ConfigFormBase {
'#title' => t('Page cache maximum age'),
'#default_value' => $config->get('cache.page.max_age'),
'#options' => $period,
'#description' => t('The maximum time a page can be cached. This is used as the value for max-age in Cache-Control headers.'),
);
$form['caching']['cache'] = array(
'#type' => 'checkbox',
'#title' => t('Use internal page cache'),
'#description' => t("If a reverse proxy cache isn't available, use Drupal's internal cache system to store cached pages."),
'#default_value' => $config->get('cache.page.use_internal'),
'#description' => t('The maximum time a page can be cached by browsers and proxies. This is used as the value for max-age in Cache-Control headers.'),
);
$directory = 'public://';
@ -157,16 +151,6 @@ class PerformanceForm extends ConfigFormBase {
'#description' => t('External resources can be optimized automatically, which can reduce both the size and number of requests made to your website.') . $disabled_message,
);
$form['bandwidth_optimization']['page_compression'] = array(
'#type' => 'checkbox',
'#title' => t('Compress cached pages'),
'#default_value' => $config->get('response.gzip'),
'#states' => array(
'visible' => array(
'input[name="cache"]' => array('checked' => TRUE),
),
),
);
$form['bandwidth_optimization']['preprocess_css'] = array(
'#type' => 'checkbox',
'#title' => t('Aggregate CSS files'),
@ -195,9 +179,7 @@ class PerformanceForm extends ConfigFormBase {
$this->renderCache->deleteAll();
$this->config('system.performance')
->set('cache.page.use_internal', $form_state->getValue('cache'))
->set('cache.page.max_age', $form_state->getValue('page_cache_maximum_age'))
->set('response.gzip', $form_state->getValue('page_compression'))
->set('css.preprocess', $form_state->getValue('preprocess_css'))
->set('js.preprocess', $form_state->getValue('preprocess_js'))
->save();

View File

@ -21,7 +21,6 @@ class AjaxFormPageCacheTest extends AjaxTestBase {
parent::setUp();
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
}

View File

@ -21,7 +21,6 @@ trait AssertPageCacheContextsAndTagsTrait {
*/
protected function enablePageCaching() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
}

View File

@ -31,7 +31,6 @@ abstract class PageCacheTagsTestBase extends WebTestBase {
// Enable page caching.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 3600);
$config->save();
}

View File

@ -28,7 +28,6 @@ class FormStoragePageCacheTest extends WebTestBase {
parent::setUp();
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
}

View File

@ -155,16 +155,14 @@ class SessionTest extends WebTestBase {
function testEmptyAnonymousSession() {
// Verify that no session is automatically created for anonymous user when
// page caching is disabled.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 0);
$config->save();
$this->container->get('module_installer')->uninstall(['page_cache']);
$this->drupalGet('');
$this->assertSessionCookie(FALSE);
$this->assertSessionEmpty(TRUE);
// The same behavior is expected when caching is enabled.
$this->container->get('module_installer')->install(['page_cache']);
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
$this->drupalGet('');

View File

@ -160,12 +160,7 @@ class ErrorHandlerTest extends WebTestBase {
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
$this->assertErrorMessage($error_renderer_exception);
// Enable the page cache and disable error reporting, ensure that 5xx
// responses are not cached.
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
// Disable error reporting, ensure that 5xx responses are not cached.
$this->config('system.logging')
->set('error_level', ERROR_REPORTING_HIDE)
->save();

View File

@ -38,31 +38,10 @@ class SiteMaintenanceTest extends WebTestBase {
$this->drupalLogin($this->adminUser);
}
/**
* Verify site maintenance mode functionality with page cache disabled.
*/
function testSiteMaintenanceWithoutPageCache() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 0);
$config->save();
$this->doTestSiteMaintenance();
}
/**
* Verify site maintenance mode functionality with page cache enabled.
*/
function testSiteMaintenanceWithPageCache() {
$config = $this->config('system.performance');
$config->set('cache.page.use_internal', 1);
$config->set('cache.page.max_age', 300);
$config->save();
$this->doTestSiteMaintenance();
}
/**
* Verify site maintenance mode functionality.
*/
protected function doTestSiteMaintenance() {
protected function testSiteMaintenance() {
// Turn on maintenance mode.
$edit = array(
'maintenance_mode' => 1,

View File

@ -1,20 +0,0 @@
cache:
page:
# @todo: Remove this file in https://www.drupal.org/node/2368987, update the
# install profile's YAML file to depend on the page_cache module instead.
use_internal: true
max_age: 0
css:
preprocess: true
gzip: true
fast_404:
enabled: true
paths: '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'
exclude_paths: '/\/(?:styles|imagecache)\//'
html: '<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>'
js:
preprocess: true
gzip: true
response:
gzip: false
stale_file_threshold: 2592000

View File

@ -7,5 +7,6 @@ dependencies:
- node
- block
- dblog
- page_cache
themes:
- stark

View File

@ -1,20 +0,0 @@
cache:
page:
# @todo: Remove this file in https://www.drupal.org/node/2368987, update the
# install profile's YAML file to depend on the page_cache module instead.
use_internal: true
max_age: 0
css:
preprocess: true
gzip: true
fast_404:
enabled: true
paths: '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'
exclude_paths: '/\/(?:styles|imagecache)\//'
html: '<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>'
js:
preprocess: true
gzip: true
response:
gzip: false
stale_file_threshold: 2592000

View File

@ -25,6 +25,7 @@ dependencies:
- menu_ui
- options
- path
- page_cache
- taxonomy
- dblog
- search

View File

@ -1,20 +0,0 @@
cache:
page:
# @todo: Remove this file in https://www.drupal.org/node/2368987, update the
# install profile's YAML file to depend on the page_cache module instead.
use_internal: true
max_age: 0
css:
preprocess: true
gzip: true
fast_404:
enabled: true
paths: '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'
exclude_paths: '/\/(?:styles|imagecache)\//'
html: '<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>'
js:
preprocess: true
gzip: true
response:
gzip: false
stale_file_threshold: 2592000

View File

@ -4,6 +4,10 @@ description: 'Minimal profile for running tests. Includes absolutely required mo
version: VERSION
core: 8.x
hidden: true
dependencies:
# Enable page_cache in testing, to ensure that as many tests as possible run
# with page caching enabled.
- page_cache
# @todo: Remove this in https://www.drupal.org/node/2352949
themes:
- classy

View File

@ -74,13 +74,6 @@ class FormCacheTest extends UnitTestCase {
*/
protected $logger;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $configFactory;
/**
* The request stack.
*
@ -121,11 +114,10 @@ class FormCacheTest extends UnitTestCase {
$this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
$this->logger = $this->getMock('Psr\Log\LoggerInterface');
$this->configFactory = $this->getConfigFactoryStub(['system.performance' => ['cache.page.use_internal' => FALSE]]);
$this->requestStack = $this->getMock('\Symfony\Component\HttpFoundation\RequestStack');
$this->requestPolicy = $this->getMock('\Drupal\Core\PageCache\RequestPolicyInterface');
$this->formCache = new FormCache($this->root, $this->keyValueExpirableFactory, $this->moduleHandler, $this->account, $this->csrfToken, $this->logger, $this->configFactory, $this->requestStack, $this->requestPolicy);
$this->formCache = new FormCache($this->root, $this->keyValueExpirableFactory, $this->moduleHandler, $this->account, $this->csrfToken, $this->logger, $this->requestStack, $this->requestPolicy);
}
/**
@ -486,43 +478,6 @@ class FormCacheTest extends UnitTestCase {
$this->formCache->setCache($form_build_id, $form, $form_state);
}
/**
* @covers ::setCache
*/
public function testSetCacheImmutableForm() {
$form_build_id = 'the_form_build_id';
$form = [
'#form_id' => 'the_form_id',
];
$form_state = new FormState();
$this->formCacheStore->expects($this->once())
->method('setWithExpire')
->with($form_build_id, $form, $this->isType('int'));
$form_state_data = $form_state->getCacheableArray();
$form_state_data['build_info']['safe_strings'] = [];
// Ensure that the form is marked immutable.
$form_state_data['build_info']['immutable'] = TRUE;
$this->formStateCacheStore->expects($this->once())
->method('setWithExpire')
->with($form_build_id, $form_state_data, $this->isType('int'));
// Rebuild the FormCache with a config factory that will return a config
// object with the internal page cache enabled.
$this->configFactory = $this->getConfigFactoryStub(['system.performance' => ['cache.page.use_internal' => TRUE]]);
$root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
$this->formCache = $this->getMockBuilder('Drupal\Core\Form\FormCache')
->setConstructorArgs([$root, $this->keyValueExpirableFactory, $this->moduleHandler, $this->account, $this->csrfToken, $this->logger, $this->configFactory, $this->requestStack, $this->requestPolicy])
->setMethods(['isPageCacheable'])
->getMock();
$this->formCache->expects($this->once())
->method('isPageCacheable')
->willReturn(TRUE);
$this->formCache->setCache($form_build_id, $form, $form_state);
}
/**
* Ensures SafeMarkup does not bleed from one test to another.
*/