Commit 6325f60a authored by catch's avatar catch

Issue #2644598 by mglaman, bojanz, vasike: Views forms can't be used multiple...

Issue #2644598 by mglaman, bojanz, vasike: Views forms can't be used multiple times on the same page
parent e825a16a
......@@ -65,6 +65,13 @@ class ViewsForm implements FormInterface, ContainerInjectionInterface {
*/
protected $viewDisplayId;
/**
* The arguments passed to the active view.
*
* @var string[]
*/
protected $viewArguments;
/**
* Constructs a ViewsForm object.
*
......@@ -78,37 +85,60 @@ class ViewsForm implements FormInterface, ContainerInjectionInterface {
* The ID of the view.
* @param string $view_display_id
* The ID of the active view's display.
* @param string[] $view_args
* The arguments passed to the active view.
*/
public function __construct(ClassResolverInterface $class_resolver, UrlGeneratorInterface $url_generator, RequestStack $requestStack, $view_id, $view_display_id) {
public function __construct(ClassResolverInterface $class_resolver, UrlGeneratorInterface $url_generator, RequestStack $requestStack, $view_id, $view_display_id, array $view_args) {
$this->classResolver = $class_resolver;
$this->urlGenerator = $url_generator;
$this->requestStack = $requestStack;
$this->viewId = $view_id;
$this->viewDisplayId = $view_display_id;
$this->viewArguments = $view_args;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL) {
public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL, array $view_args = NULL) {
return new static(
$container->get('class_resolver'),
$container->get('url_generator'),
$container->get('request_stack'),
$view_id,
$view_display_id
$view_display_id,
$view_args
);
}
/**
* {@inheritdoc}
* Returns a string for the form's base ID.
*
* @return string
* The string identifying the form's base ID.
*/
public function getFormId() {
$parts = array(
public function getBaseFormId() {
$parts = [
'views_form',
$this->viewId,
$this->viewDisplayId,
);
];
return implode('_', $parts);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
$parts = [
$this->getBaseFormId(),
];
if (!empty($this->viewArguments)) {
// Append the passed arguments to ensure form uniqueness.
$parts = array_merge($parts, $this->viewArguments);
}
return implode('_', $parts);
}
......@@ -123,6 +153,9 @@ public function buildForm(array $form, FormStateInterface $form_state, ViewExecu
}
$form_state->set(['step_controller', 'views_form_views_form'], 'Drupal\views\Form\ViewsFormMainForm');
// Add the base form ID.
$form_state->addBuildInfo('base_form_id', $this->getBaseFormId());
$form = array();
$query = $this->requestStack->getCurrentRequest()->query->all();
......
......@@ -2195,7 +2195,7 @@ public function elementPreRender(array $element) {
$output = $element['#empty'];
}
$form_object = ViewsForm::create(\Drupal::getContainer(), $view->storage->id(), $view->current_display);
$form_object = ViewsForm::create(\Drupal::getContainer(), $view->storage->id(), $view->current_display, $view->args);
$form = \Drupal::formBuilder()->getForm($form_object, $view, $output);
// The form is requesting that all non-essential views elements be hidden,
// usually because the rendered step is not a view result.
......
<?php
/**
* @file
* Contains \Drupal\views\Tests\ViewsFormMultipleTest.
*/
namespace Drupal\views\Tests;
/**
* Tests a page with multiple Views forms.
*
* @group views
*/
class ViewsFormMultipleTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_form_multiple'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->enableViewsTestModule();
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['field_form_button_test']['field'] = [
'title' => t('Button test'),
'help' => t('Adds a test form button.'),
'id' => 'field_form_button_test',
];
return $data;
}
/**
* Tests the a page with multiple View forms in it.
*/
public function testViewsFormMultiple() {
// Get the test page.
$this->drupalGet('views_test_form_multiple');
$this->assertText('Test base form ID with Views forms and arguments.');
// Submit the forms, validate argument returned in message set by handler.
// @note There is not a way to specify a specific index for a submit button. So
// the row index returned is always the last occurrence.
$this->drupalPostForm(NULL, [], t('Test Button'), [], [], 'views-form-test-form-multiple-default-arg2');
$this->assertText('The test button at row 4 for test_form_multiple (default) View with args: arg2 was submitted.');
$this->drupalPostForm(NULL, [], t('Test Button'), [], [], 'views-form-test-form-multiple-default-arg1');
$this->assertText('The test button at row 4 for test_form_multiple (default) View with args: arg1 was submitted.');
}
}
langcode: en
status: true
dependencies:
module:
- node
id: test_form_multiple
label: ''
module: views
description: ''
tag: ''
base_table: views_test_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
display_title: Master
id: default
position: 0
display_options:
access:
type: none
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
pager:
options:
id: 0
items_per_page: 10
offset: 0
type: full
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: false
caption: ''
summary: ''
description: ''
columns:
id: id
field_form_button_test: field_form_button_test
info:
field_form_button_test:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: '-1'
empty_table: false
row:
type: fields
fields:
id:
field: id
id: id
relationship: none
table: views_test_data
plugin_id: numeric
field_form_button_test:
id: field_form_button_test
table: views_test_data
field: field_form_button_test
relationship: none
group_type: group
admin_label: ''
label: 'Field form button test'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: field_form_button_test
arguments:
'null':
default_action: default
default_argument_type: fixed
field: 'null'
id: 'null'
must_not_be: false
table: views
plugin_id: 'null'
<?php
/**
* @file
* Contains \Drupal\views_test_data\Controller\ViewsTestFormMultipleController.
*/
namespace Drupal\views_test_data\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Controller routines for views form multiple test routes.
*/
class ViewsTestFormMultipleController extends ControllerBase {
/**
* Returns a test page having test_form_multiple view embedded twice.
*/
public function testPage() {
$build = [
'view_arg1' => [
'#prefix' => '<div class="view-test-form-multiple-1">',
'#suffix' => '</div>',
'#type' => 'view',
'#name' => 'test_form_multiple',
'#display_id' => 'default',
'#arguments' => ['arg1'],
'#embed' => TRUE,
],
'view_arg2' => [
'#prefix' => '<div class="view-test-form-multiple-2">',
'#suffix' => '</div>',
'#type' => 'view',
'#name' => 'test_form_multiple',
'#display_id' => 'default',
'#arguments' => ['arg2'],
'#embed' => TRUE,
],
];
return $build;
}
}
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\field\FieldFormButtonTest.
*/
namespace Drupal\views_test_data\Plugin\views\field;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\Plugin\views\field\UncacheableFieldHandlerTrait;
use Drupal\views\ResultRow;
/**
* A handler to provide a field that is completely custom by the administrator.
*
* @ingroup views_field_handlers
*
* @ViewsField("field_form_button_test")
*/
class FieldFormButtonTest extends FieldPluginBase {
use UncacheableFieldHandlerTrait;
/**
* {@inheritdoc}
*/
public function getValue(ResultRow $row, $field = NULL) {
return '<!--form-item-' . $this->options['id'] . '--' . $row->index . '-->';
}
/**
* Form constructor for the views form.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function viewsForm(&$form, FormStateInterface $form_state) {
// Make sure we do not accidentally cache this form.
$form['#cache']['max-age'] = 0;
// The view is empty, abort.
if (empty($this->view->result)) {
unset($form['actions']);
return;
}
$form[$this->options['id']]['#tree'] = TRUE;
foreach ($this->view->result as $row_index => $row) {
$form[$this->options['id']][$row_index] = [
'#type' => 'submit',
'#value' => t('Test Button'),
'#name' => 'test-button-' . $row_index,
'#test_button' => TRUE,
'#row_index' => $row_index,
'#attributes' => ['class' => ['test-button']],
];
}
}
/**
* Submit handler for the views form.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function viewsFormSubmit(&$form, FormStateInterface $form_state) {
$triggering_element = $form_state->getTriggeringElement();
if (!empty($triggering_element['#test_button'])) {
$row_index = $triggering_element['#row_index'];
$view_args = !empty($this->view->args) ? implode(', ', $this->view->args) : $this->t('no arguments');
drupal_set_message($this->t('The test button at row @row_index for @view_id (@display) View with args: @args was submitted.', [
'@display' => $this->view->current_display,
'@view_id' => $this->view->id(),
'@args' => $view_args,
'@row_index' => $row_index,
]));
}
}
/**
* {@inheritdoc}
*/
public function query() {
// Do nothing.
}
}
......@@ -122,3 +122,10 @@ function views_test_data_test_pre_render_function($element) {
$element['#markup'] = 'views_test_data_test_pre_render_function executed';
return $element;
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function views_test_data_form_views_form_test_form_multiple_default_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
drupal_set_message(t('Test base form ID with Views forms and arguments.'));
}
......@@ -11,3 +11,11 @@ views_test_data.element_embed:
_form: '\Drupal\views_test_data\Form\ViewsTestDataElementEmbedForm'
requirements:
_access: 'TRUE'
views_test_data.form_multiple:
path: '/views_test_form_multiple'
defaults:
_title: 'Test Views Form Multiple'
_controller: '\Drupal\views_test_data\Controller\ViewsTestFormMultipleController::testPage'
requirements:
_access: 'TRUE'
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