Commit 5818a99b authored by Dries's avatar Dries

Issue #512026 by Berdir, effulgentsia, sun, marcingy, Eric_A, xjm, katbailey,...

Issue #512026 by Berdir, effulgentsia, sun, marcingy, Eric_A, xjm, katbailey, Damien Tournoud, alexpott, beejeebus, pillarsdotnet: Move () storage from cache to new state/key-value system.
parent 0bb14c81
......@@ -6369,8 +6369,7 @@ function drupal_flush_all_caches() {
// sufficient, since new extensions cannot have any primed caches yet.
module_invoke_all('cache_flush');
foreach (Cache::getBins() as $service_id => $cache_backend) {
// @todo remove form after http://drupal.org/node/512026 is in.
if ($service_id != 'cache.form' && $service_id != 'cache.menu') {
if ($service_id != 'cache.menu') {
$cache_backend->deleteAll();
}
}
......
......@@ -530,14 +530,12 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
* Fetches a form from the cache.
*/
function form_get_cache($form_build_id, &$form_state) {
if ($cached = cache('form')->get('form_' . $form_build_id)) {
$form = $cached->data;
if ($form = Drupal::keyValueExpirable('form')->get($form_build_id)) {
global $user;
if ((isset($form['#cache_token']) && drupal_valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid)) {
if ($cached = cache('form')->get('form_state_' . $form_build_id)) {
if ($stored_form_state = Drupal::keyValueExpirable('form_state')->get($form_build_id)) {
// Re-populate $form_state for subsequent rebuilds.
$form_state = $cached->data + $form_state;
$form_state = $stored_form_state + $form_state;
// If the original form is contained in include files, load the files.
// @see form_load_include()
......@@ -569,12 +567,12 @@ function form_set_cache($form_build_id, $form, $form_state) {
if ($GLOBALS['user']->uid) {
$form['#cache_token'] = drupal_get_token();
}
cache('form')->set('form_' . $form_build_id, $form, REQUEST_TIME + $expire);
Drupal::keyValueExpirable('form')->setWithExpire($form_build_id, $form, $expire);
}
// Cache form state.
if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) {
cache('form')->set('form_state_' . $form_build_id, $data, REQUEST_TIME + $expire);
Drupal::keyValueExpirable('form_state')->setWithExpire($form_build_id, $data, $expire);
}
}
......@@ -916,15 +914,6 @@ function drupal_process_form($form_id, &$form, &$form_state) {
// Execute form submit handlers.
form_execute_handlers('submit', $form, $form_state);
// We'll clear out the cached copies of the form and its stored data
// here, as we've finished with them. The in-memory copies are still
// here, though.
$config = config('system.performance');
if (!$config->get('cache.page.use_internal') && !empty($form_state['values']['form_build_id'])) {
cache('form')->delete('form_' . $form_state['values']['form_build_id']);
cache('form')->delete('form_state_' . $form_state['values']['form_build_id']);
}
// If batches were set in the submit handlers, we process them now,
// possibly ending execution. We make sure we do not react to the batch
// that is already being processed (if a batch operation performs a
......
......@@ -350,7 +350,7 @@ function install_begin_request(&$install_state) {
// Register the 'language_manager' service.
$container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
foreach (array('bootstrap', 'config', 'cache', 'form', 'menu', 'page', 'path') as $bin) {
foreach (array('bootstrap', 'config', 'cache', 'menu', 'page', 'path') as $bin) {
$container
->register("cache.$bin", 'Drupal\Core\Cache\MemoryBackend')
->addArgument($bin);
......@@ -379,6 +379,14 @@ function install_begin_request(&$install_state) {
))
->addMethodCall('setUserAgent', array('Drupal (+http://drupal.org/)'));
// Register the expirable key value store used by form cache.
$container
->register('keyvalue.expirable', 'Drupal\Core\KeyValueStore\KeyValueExpirableFactory')
->addArgument(new Reference('service_container'));
$container
->register('keyvalue.expirable.null', 'Drupal\Core\KeyValueStore\KeyValueNullExpirableFactory');
$conf['keyvalue_expirable_default'] = 'keyvalue.expirable.null';
Drupal::setContainer($container);
}
......
......@@ -451,7 +451,7 @@ protected function registerCache(ContainerBuilder $container) {
$container
->register('cache.backend.memory', 'Drupal\Core\Cache\MemoryBackendFactory');
// Register a service for each bin for injecting purposes.
foreach (array('bootstrap', 'config', 'cache', 'form', 'menu', 'page', 'path') as $bin) {
foreach (array('bootstrap', 'config', 'cache', 'menu', 'page', 'path') as $bin) {
CacheFactory::registerBin($container, $bin);
}
......
<?php
/**
* @file
* Contains \Drupal\Core\KeyValueStore\KeyValueNullExpirableFactory.
*/
namespace Drupal\Core\KeyValueStore;
/**
* Defines the key/value store factory for the null backend.
*/
class KeyValueNullExpirableFactory {
/**
* Constructs a new key/value expirable null storage object for a given
* collection name.
*
* @param string $collection
* The name of the collection holding key and value pairs.
*
* @return \Drupal\Core\KeyValueStore\DatabaseStorageExpirable
* A key/value store implementation for the given $collection.
*/
public function get($collection) {
return new NullStorageExpirable($collection);
}
}
<?php
/**
* @file
* Contains \Drupal\Core\KeyValueStore\NullStorageExpirable.
*/
namespace Drupal\Core\KeyValueStore;
/**
* Defines a null key/value store implementation.
*/
class NullStorageExpirable implements KeyValueStoreExpirableInterface {
/**
* The actual storage of key-value pairs.
*
* @var array
*/
protected $data = array();
/**
* The name of the collection holding key and value pairs.
*
* @var string
*/
protected $collection;
/**
* Creates a new expirable null key/value store.
*/
public function __construct($collection) {
$this->collection = $collection;
}
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::get().
*/
public function get($key) {
return NULL;
}
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::getMultiple().
*/
public function getMultiple(array $keys) {
return array();
}
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::getAll().
*/
public function getAll() {
return array();
}
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::set().
*/
public function set($key, $value) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setIfNotExists().
*/
public function setIfNotExists($key, $value) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setMultiple().
*/
public function setMultiple(array $data) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::delete().
*/
public function delete($key) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::deleteMultiple().
*/
public function deleteMultiple(array $keys) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::deleteAll().
*/
public function deleteAll() { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::getCollectionName().
*/
public function getCollectionName() {
return $this->collection;
}
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface::setMultipleWithExpire().
*/
public function setMultipleWithExpire(array $data, $expire) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface::setWithExpire().
*/
public function setWithExpire($key, $value, $expire) { }
/**
* Implements Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface::setWithExpireIfNotExists().
*/
public function setWithExpireIfNotExists($key, $value, $expire) { }
}
......@@ -35,8 +35,6 @@ function setUp() {
function testFlushAllCaches() {
// Create cache entries for each flushed cache bin.
$bins = Cache::getBins();
// @todo remove after http://drupal.org/node/512026
unset($bins['form']);
$this->assertTrue($bins, 'cache_get_bins() returned bins to flush.');
$bins['menu'] = $this->container->get('cache.menu');
foreach ($bins as $bin => $cache_backend) {
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Form\FormCacheTest.
*/
namespace Drupal\system\Tests\Form;
use Drupal\simpletest\DrupalUnitTestBase;
/**
* Tests form caching.
*/
class FormCacheTest extends DrupalUnitTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'user');
public static function getInfo() {
return array(
'name' => 'Form cache tests',
'description' => 'Tests form_set_cache() and form_get_cache()',
'group' => 'Form API',
);
}
public function setUp() {
parent::setUp();
$this->installSchema('system', array('key_value_expire'));
$this->form_build_id = $this->randomName();
$this->form = array(
'#property' => $this->randomName(),
);
$this->form_state = form_state_defaults();
$this->form_state['example'] = $this->randomName();
}
/**
* Tests the form cache with a logged-in user.
*/
function testCacheToken() {
$GLOBALS['user']->uid = 1;
form_set_cache($this->form_build_id, $this->form, $this->form_state);
$cached_form_state = form_state_defaults();
$cached_form = form_get_cache($this->form_build_id, $cached_form_state);
$this->assertEqual($this->form['#property'], $cached_form['#property']);
$this->assertTrue(!empty($cached_form['#cache_token']), 'Form has a cache token');
$this->assertEqual($this->form_state['example'], $cached_form_state['example']);
// Test that the form cache isn't loaded when the session/token has changed.
// Change the private key. (We cannot change the session ID because this
// will break the parent site test runner batch.)
state()->set('system.private_key', 'invalid');
$cached_form_state = form_state_defaults();
$cached_form = form_get_cache($this->form_build_id, $cached_form_state);
$this->assertFalse($cached_form, 'No form returned from cache');
$this->assertTrue(empty($cached_form_state['example']));
// Test that loading the cache with a different form_id fails.
$wrong_form_build_id = $this->randomName(9);
$cached_form_state = form_state_defaults();
$this->assertFalse(form_get_cache($wrong_form_build_id, $cached_form_state), 'No form returned from cache');
$this->assertTrue(empty($cached_form_state['example']), 'Cached form state was not loaded');
}
/**
* Tests the form cache without a logged-in user.
*/
function testNoCacheToken() {
$GLOBALS['user']->uid = 0;
$this->form_state['example'] = $this->randomName();
form_set_cache($this->form_build_id, $this->form, $this->form_state);
$cached_form_state = form_state_defaults();
$cached_form = form_get_cache($this->form_build_id, $cached_form_state);
$this->assertEqual($this->form['#property'], $cached_form['#property']);
$this->assertTrue(empty($cached_form['#cache_token']), 'Form has no cache token');
$this->assertEqual($this->form_state['example'], $cached_form_state['example']);
}
}
......@@ -684,8 +684,6 @@ function system_schema() {
$schema['cache_bootstrap']['description'] = 'Cache table for data required to bootstrap Drupal, may be routed to a shared memory cache.';
$schema['cache_config'] = $schema['cache'];
$schema['cache_config']['description'] = 'Cache table for configuration data.';
$schema['cache_form'] = $schema['cache'];
$schema['cache_form']['description'] = 'Cache table for the form system to store recently built forms and their storage data, to be used in subsequent page requests.';
$schema['cache_page'] = $schema['cache'];
$schema['cache_page']['description'] = 'Cache table used to store compressed pages for anonymous users, if page caching is enabled.';
$schema['cache_menu'] = $schema['cache'];
......@@ -2171,6 +2169,13 @@ function system_update_8052() {
));
}
/**
* Remove {cache_form} table.
*/
function system_update_8052() {
db_drop_table('cache_form');
}
/**
* @} End of "defgroup updates-7.x-to-8.x".
* The next series of updates should start at 9000.
......
......@@ -38,7 +38,7 @@ public static function getInfo() {
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('menu_router', 'variable'));
$this->installSchema('system', array('menu_router', 'variable', 'key_value_expire'));
}
function viewsData() {
......
......@@ -39,7 +39,7 @@ public static function getInfo() {
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('menu_router', 'variable'));
$this->installSchema('system', array('menu_router', 'variable', 'key_value_expire'));
}
function viewsData() {
......
......@@ -39,7 +39,7 @@ public static function getInfo() {
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('menu_router', 'variable'));
$this->installSchema('system', array('menu_router', 'variable', 'key_value_expire'));
}
function viewsData() {
......
......@@ -38,7 +38,7 @@ public static function getInfo() {
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('menu_router', 'variable'));
$this->installSchema('system', array('menu_router', 'variable', 'key_value_expire'));
}
function viewsData() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment