Commit d1c03228 authored by alexpott's avatar alexpott

Issue #2252763 by damiankloip, skipyT, martin107, dawehner, dashaforbes: Views...

Issue #2252763 by damiankloip, skipyT, martin107, dawehner, dashaforbes: Views exposed filter form causes enormous form state cache entries
parent b5500b61
......@@ -62,18 +62,15 @@ public function testBulkForm() {
$this->assertTrue($node->isPublished(), 'Node has been published');
// Make sticky action.
$node->setPublished(FALSE);
$node->save();
$this->assertFalse($node->isSticky(), 'Node is not sticky');
$edit = array(
'node_bulk_form[0]' => TRUE,
'action' => 'node_make_sticky_action',
);
$this->drupalPostForm(NULL, $edit, t('Apply'));
// Re-load the node and check the status and sticky flag.
// Re-load the node and check the sticky flag.
$node_storage->resetCache(array($node->id()));
$node = $node_storage->load($node->id());
$this->assertTrue($node->isPublished(), 'Node has been published');
$this->assertTrue($node->isSticky(), 'Node has been made sticky');
// Make unsticky action.
......@@ -88,18 +85,15 @@ public function testBulkForm() {
$this->assertFalse($node->isSticky(), 'Node is not sticky anymore');
// Promote to front page.
$node->setPublished(FALSE);
$node->save();
$this->assertFalse($node->isPromoted(), 'Node is not promoted to the front page');
$edit = array(
'node_bulk_form[0]' => TRUE,
'action' => 'node_promote_action',
);
$this->drupalPostForm(NULL, $edit, t('Apply'));
// Re-load the node and check the status and promoted flag.
// Re-load the node and check the promoted flag.
$node_storage->resetCache(array($node->id()));
$node = $node_storage->load($node->id());
$this->assertTrue($node->isPublished(), 'Node has been published');
$this->assertTrue($node->isPromoted(), 'Node has been promoted to the front page');
// Demote from front page.
......
......@@ -433,4 +433,13 @@ public function isInstallable() {
return (bool) \Drupal::service('views.views_data')->get($this->base_table);
}
/**
* {@inheritdoc}
*/
public function __sleep() {
$keys = parent::__sleep();
unset($keys[array_search('executable', $keys)]);
return $keys;
}
}
......@@ -121,7 +121,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
$form['#id'] = Html::cleanCssIdentifier('views_exposed_form-' . String::checkPlain($view->storage->id()) . '-' . String::checkPlain($display['id']));
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
$exposed_form_plugin = $form_state->get('exposed_form_plugin');
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
$exposed_form_plugin->exposedFormAlter($form, $form_state);
// Save the form.
......@@ -134,15 +134,17 @@ public function buildForm(array $form, FormStateInterface $form_state) {
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$view = $form_state->get('view');
foreach (array('field', 'filter') as $type) {
/** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
$handlers = &$form_state->get('view')->$type;
$handlers = &$view->$type;
foreach ($handlers as $key => $handler) {
$handlers[$key]->validateExposed($form, $form_state);
}
}
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
$exposed_form_plugin = $form_state->get('exposed_form_plugin');
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
$exposed_form_plugin->exposedFormValidate($form, $form_state);
}
......@@ -157,13 +159,14 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
$handlers[$key]->submitExposed($form, $form_state);
}
}
$view = $form_state->get('view');
$view->exposed_data = $form_state->getValues();
$view->exposed_raw_input = [];
$exclude = array('submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', '', 'reset');
$exclude = array('submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset');
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
$exposed_form_plugin = $form_state->get('exposed_form_plugin');
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
$exposed_form_plugin->exposedFormSubmit($form, $form_state, $exclude);
foreach ($form_state->getValues() as $key => $value) {
......
......@@ -150,7 +150,6 @@ public function renderExposedForm($block = FALSE) {
$form_state->set('ajax', TRUE);
}
$form_state->set('exposed_form_plugin', $this);
$form = \Drupal::formBuilder()->buildForm('\Drupal\views\Form\ViewsExposedForm', $form_state);
if (!$this->view->display_handler->displaysExposed() || (!$block && $this->view->display_handler->getOption('exposed_block'))) {
......
......@@ -54,6 +54,13 @@
*/
abstract class RelationshipPluginBase extends HandlerBase {
/**
* The relationship alias.
*
* @var string
*/
public $alias;
/**
* Overrides \Drupal\views\Plugin\views\HandlerBase::init().
*
......
......@@ -449,6 +449,7 @@ public function testValidateNestedLoops() {
$errors = $executable->validate();
$total_error_count = array_reduce($errors, function ($carry, $item) {
$carry += count($item);
return $carry;
});
// Assert that there were 9 total errors across 3 displays.
......@@ -456,4 +457,29 @@ public function testValidateNestedLoops() {
$this->assertIdentical(3, count($errors));
}
/**
* Tests serialization of the ViewExecutable object.
*/
public function testSerialization() {
$view = Views::getView('test_executable_displays');
$view->setDisplay('page_1');
$view->setArguments(['test']);
$view->setCurrentPage(2);
$serialized = serialize($view);
// Test the view storage object is not present in the actual serialized
// string.
$this->assertIdentical(strpos($serialized, '"Drupal\views\Entity\View"'), FALSE, 'The Drupal\views\Entity\View class was not found in the serialized string.');
/** @var \Drupal\views\ViewExecutable $unserialized */
$unserialized = unserialize($serialized);
$this->assertTrue($unserialized instanceof ViewExecutable);
$this->assertIdentical($view->storage->id(), $unserialized->storage->id(), 'The expected storage entity was loaded on the unserialized view.');
$this->assertIdentical($unserialized->current_display, 'page_1', 'The expected display was set on the unserialized view.');
$this->assertIdentical($unserialized->args, ['test'], 'The expected argument was set on the unserialized view.');
$this->assertIdentical($unserialized->getCurrentPage(), 2, 'The expected current page was set on the unserialized view.');
}
}
......@@ -26,7 +26,7 @@
* An object to contain all of the data to generate a view, plus the member
* functions to build the view query, execute the query and render the output.
*/
class ViewExecutable {
class ViewExecutable implements \Serializable {
use DependencySerializationTrait;
/**
......@@ -2295,4 +2295,49 @@ public function calculateDependencies() {
return $this->storage->calculateDependencies();
}
/**
* {@inheritdoc}
*/
public function serialize() {
return serialize([
// Only serialize the storage entity ID.
$this->storage->id(),
$this->current_display,
$this->args,
$this->current_page,
$this->exposed_input,
$this->exposed_raw_input,
$this->exposed_data,
$this->dom_id,
$this->executed,
]);
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized) {
list($storage, $current_display, $args, $current_page, $exposed_input, $exposed_raw_input, $exposed_data, $dom_id, $executed) = unserialize($serialized);
$this->setRequest(\Drupal::request());
$this->user = \Drupal::currentUser();
$this->storage = \Drupal::entityManager()->getStorage('view')->load($storage);
$this->setDisplay($current_display);
$this->setArguments($args);
$this->setCurrentPage($current_page);
$this->setExposedInput($exposed_input);
$this->exposed_data = $exposed_data;
$this->exposed_raw_input = $exposed_raw_input;
$this->dom_id = $dom_id;
$this->initHandlers();
// If the display was previously executed, execute it now.
if ($executed) {
$this->execute($this->current_display);
}
}
}
......@@ -266,6 +266,7 @@ public function validate(array $form, FormStateInterface $form_state) {
public function save(array $form, FormStateInterface $form_state) {
$view = $this->entity;
$executable = $view->getExecutable();
$executable->initDisplay();
// Go through and remove displayed scheduled for removal.
$displays = $view->get('display');
......
This diff is collapsed.
......@@ -9,6 +9,7 @@
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Entity\View;
use Drupal\views\ViewExecutable;
use Drupal\views_ui\ViewUI;
use Symfony\Component\DependencyInjection\Container;
......@@ -54,8 +55,9 @@ public function testEntityDecoration() {
->disableOriginalConstructor()
->setConstructorArgs(array($storage))
->getMock();
$storage->set('executable', $executable);
$view_ui = new ViewUI($storage, $executable);
$view_ui = new ViewUI($storage);
foreach ($method_args as $method => $args) {
$method_mock = $storage->expects($this->once())
......@@ -80,6 +82,7 @@ public function testIsLocked() {
->disableOriginalConstructor()
->setConstructorArgs(array($storage))
->getMock();
$storage->set('executable', $executable);
$account = $this->getMock('Drupal\Core\Session\AccountInterface');
$account->expects($this->exactly(2))
->method('id')
......@@ -89,7 +92,7 @@ public function testIsLocked() {
$container->set('current_user', $account);
\Drupal::setContainer($container);
$view_ui = new ViewUI($storage, $executable);
$view_ui = new ViewUI($storage);
// A view_ui without a lock object is not locked.
$this->assertFalse($view_ui->isLocked());
......@@ -113,4 +116,33 @@ public function testIsLocked() {
$this->assertFalse($view_ui->isLocked());
}
/**
* Tests serialization of the ViewUI object.
*/
public function testSerialization() {
// Set a container so the DependencySerializationTrait has it.
$container = new ContainerBuilder();
\Drupal::setContainer($container);
$storage = new View([], 'view');
$executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
->disableOriginalConstructor()
->setConstructorArgs([$storage])
->getMock();
$storage->set('executable', $executable);
$view_ui = new ViewUI($storage);
// Make sure the executable is returned before serializing.
$this->assertInstanceOf('Drupal\views\ViewExecutable', $view_ui->getExecutable());
$serialized = serialize($view_ui);
// Make sure the ViewExecutable class is not found in the serialized string.
$this->assertSame(strpos($serialized, '"Drupal\views\ViewExecutable"'), FALSE);
$unserialized = unserialize($serialized);
$this->assertInstanceOf('Drupal\views_ui\ViewUI', $unserialized);
}
}
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