Unverified Commit 09fdae11 authored by larowlan's avatar larowlan

Issue #1886018 by dagmar, Munavijayalakshmi, Lendude, Manuel Garcia, abi_cima,...

Issue #1886018 by dagmar, Munavijayalakshmi, Lendude, Manuel Garcia, abi_cima, alexpott: Make it possible to configure exposed filter operators
parent 83fd8cc9
......@@ -375,6 +375,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -416,6 +418,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
langcode: und
status: true
dependencies:
module:
- datetime
- node
id: test_exposed_filter_datetime
label: test_exposed_filter_datetime
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: '8'
display:
default:
display_options:
access:
type: none
cache:
type: none
exposed_form:
type: basic
fields:
nid:
field: nid
id: nid
table: node_field_data
plugin_id: node
filters:
field_date_value:
id: field_date_value
table: node__field_date
field: field_date_value
relationship: none
group_type: group
admin_label: ''
operator: '='
value:
min: ''
max: ''
value: ''
type: date
group: 1
exposed: true
expose:
operator_id: field_date_value_op
label: 'field_date (field_date)'
description: ''
use_operator: true
operator: field_date_value_op
operator_limit_selection: true
operator_list:
'=': '='
'!=': '!='
identifier: field_date_value
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
placeholder: ''
min_placeholder: ''
max_placeholder: ''
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: datetime
sorts:
id:
field: nid
id: nid
order: ASC
relationship: none
table: node_field_data
plugin_id: numeric
pager:
type: full
query:
options:
query_comment: ''
type: views_query
style:
type: default
row:
type: fields
display_extenders: { }
display_plugin: default
display_title: Master
id: default
position: 0
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
tags: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: test_exposed_filter_datetime
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
tags: { }
<?php
namespace Drupal\Tests\datetime\Functional;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
/**
* Test exposed datetime filters functionality.
*
* @group views
* @see \Drupal\datetime\Plugin\views\filter\Date
*/
class DateFilterTest extends ViewTestBase {
/**
* A user with permission to administer views.
*
* @var \Drupal\user\Entity\User
*/
protected $adminUser;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_exposed_filter_datetime'];
/**
* {@inheritdoc}
*/
public static $modules = [
'datetime_test',
'node',
'datetime',
'field',
'views_ui',
];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
ViewTestData::createTestViews(get_class($this), ['datetime_test']);
// Add a date field to page nodes.
$node_type = NodeType::create([
'type' => 'page',
'name' => 'page',
]);
$node_type->save();
$fieldStorage = FieldStorageConfig::create([
'field_name' => 'field_date',
'entity_type' => 'node',
'type' => 'datetime',
'settings' => ['datetime_type' => DateTimeItem::DATETIME_TYPE_DATETIME],
]);
$fieldStorage->save();
$field = FieldConfig::create([
'field_storage' => $fieldStorage,
'bundle' => 'page',
'required' => TRUE,
]);
$field->save();
$this->adminUser = $this->drupalCreateUser(['administer views']);
$this->drupalLogin($this->adminUser);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
}
/**
* Tests the limit of the expose operator functionality.
*/
public function testLimitExposedOperators() {
$this->drupalGet('test_exposed_filter_datetime');
$this->assertResponse(200);
$this->assertOption('edit-field-date-value-op', '=');
$this->assertNoOption('edit-field-date-value-op', '>');
$this->assertNoOption('edit-field-date-value-op', '>=');
// Because there are not operators that use the min and max fields, those
// fields should not be in the exposed form.
$this->assertFieldById('edit-field-date-value-value');
$this->assertNoFieldById('edit-field-date-value-min');
$this->assertNoFieldById('edit-field-date-value-max');
$edit = [];
$edit['options[operator]'] = '>';
$edit['options[expose][operator_list][]'] = ['>', '>=', 'between'];
$this->drupalPostForm('admin/structure/views/nojs/handler/test_exposed_filter_datetime/default/filter/field_date_value', $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/test_exposed_filter_datetime/edit/default', [], t('Save'));
$this->drupalGet('test_exposed_filter_datetime');
$this->assertResponse(200);
$this->assertNoOption('edit-field-date-value-op', '<');
$this->assertNoOption('edit-field-date-value-op', '<=');
$this->assertNoOption('edit-field-date-value-op', '=');
$this->assertOption('edit-field-date-value-op', '>');
$this->assertOption('edit-field-date-value-op', '>=');
$this->assertFieldById('edit-field-date-value-value');
$this->assertFieldById('edit-field-date-value-min');
$this->assertFieldById('edit-field-date-value-max');
// Set the default to an excluded operator.
$edit = [];
$edit['options[operator]'] = '=';
$edit['options[expose][operator_list][]'] = ['<', '>'];
$this->drupalPostForm('admin/structure/views/nojs/handler/test_exposed_filter_datetime/default/filter/field_date_value', $edit, t('Apply'));
$this->assertText('You selected the "Is equal to" operator as the default value but is not included in the list of limited operators.');
}
}
......@@ -582,6 +582,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -621,6 +623,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -595,6 +595,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -635,6 +637,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -676,6 +680,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -639,6 +639,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -680,6 +682,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -718,6 +722,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: true
group_info:
label: 'Published status'
......@@ -767,6 +773,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -212,6 +212,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: true
group_info:
label: Published
......@@ -260,6 +262,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -301,6 +305,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: 'Media type'
......@@ -565,6 +571,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -605,6 +613,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -808,6 +818,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -848,6 +860,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -110,6 +110,8 @@ display:
group: 0
expose:
operator: '0'
operator_limit_selection: false
operator_list: { }
plugin_id: boolean
entity_type: node
entity_field: status
......@@ -138,6 +140,8 @@ display:
remember_roles:
authenticated: authenticated
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -378,6 +378,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -419,6 +421,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -457,6 +461,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: true
group_info:
label: 'Published status'
......@@ -506,6 +512,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -530,6 +538,9 @@ display:
plugin_id: node_status
group: 1
entity_type: node
expose:
operator_limit_selection: false
operator_list: { }
sorts: { }
title: Content
empty:
......
......@@ -185,6 +185,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -224,6 +226,8 @@ display:
remember_roles:
authenticated: authenticated
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -333,6 +333,8 @@ display:
remember_roles:
authenticated: authenticated
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -601,6 +601,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -642,6 +644,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: true
group_info:
label: Status
......@@ -691,6 +695,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -731,6 +737,8 @@ display:
anonymous: '0'
administrator: '0'
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -768,6 +776,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......@@ -809,6 +819,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -95,6 +95,8 @@ display:
id: status
expose:
operator: '0'
operator_limit_selection: false
operator_list: { }
group: 1
plugin_id: boolean
entity_type: user
......@@ -126,6 +128,8 @@ display:
multiple: false
remember_roles:
authenticated: authenticated
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -102,6 +102,8 @@ display:
id: status
expose:
operator: '0'
operator_limit_selection: false
operator_list: { }
group: 1
plugin_id: boolean
entity_type: user
......@@ -135,6 +137,8 @@ display:
authenticated: authenticated
anonymous: '0'
administrator: '0'
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
......
......@@ -701,6 +701,15 @@ views_filter:
operator:
type: string
label: 'Operator'
operator_limit_selection:
type: boolean
label: 'Limit the available operators'
operator_list:
type: sequence
label: 'List of available operators'
sequence:
type: string
label: 'Operator'
identifier:
type: string
label: 'Filter identifier'
......
......@@ -128,6 +128,8 @@ protected function defineOptions() {
'description' => ['default' => ''],
'use_operator' => ['default' => FALSE],
'operator' => ['default' => ''],
'operator_limit_selection' => ['default' => FALSE],
'operator_list' => ['default' => []],
'identifier' => ['default' => ''],
'required' => ['default' => FALSE],
'remember' => ['default' => FALSE],
......@@ -559,6 +561,36 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
'#description' => $this->t('Allow the user to choose the operator.'),
'#default_value' => !empty($this->options['expose']['use_operator']),
];
$operators = $this->operatorOptions();
if (!empty($operators) && count($operators) > 1) {
$form['expose']['operator_limit_selection'] = [
'#type' => 'checkbox',
'#title' => $this->t('Limit the available operators'),
'#description' => $this->t('Limit the available operators to be shown on the exposed filter.'),
'#default_value' => !empty($this->options['expose']['operator_limit_selection']),
'#states' => [
'visible' => [
':input[name="options[expose][use_operator]"]' => ['checked' => TRUE],
],
],
];
$form['expose']['operator_list'] = [
'#type' => 'select',
'#title' => $this->t('Restrict operators to'),
'#default_value' => $this->options['expose']['operator_list'],
'#options' => $operators,
'#multiple' => TRUE,
'#description' => $this->t('Selecting none will make all of them available.'),
'#states' => [
'visible' => [
':input[name="options[expose][operator_limit_selection]"]' => ['checked' => TRUE],
':input[name="options[expose][use_operator]"]' => ['checked' => TRUE],
],
],
];
}
$form['expose']['operator_id'] = [
'#type' => 'textfield',
'#default_value' => $this->options['expose']['operator_id'],
......@@ -623,6 +655,15 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
public function validateExposeForm($form, FormStateInterface $form_state) {
$identifier = $form_state->getValue(['options', 'expose', 'identifier']);
$this->validateIdentifier($identifier, $form_state, $form['expose']['identifier']);
$limit_operators = $form_state->getValue(['options', 'expose', 'operator_limit_selection']);
$operators_selected = $form_state->getValue(['options', 'expose', 'operator_list']);
$selected_operator = $form_state->getValue(['options', 'operator']);
if ($limit_operators && !in_array($selected_operator, $operators_selected, TRUE)) {
$form_state->setError(
$form['expose']['operator_list'],
$this->t('You selected the "@operator" operator as the default value but is not included in the list of limited operators.', ['@operator' => $this->operatorOptions()[$selected_operator]]));
}
}
/**
......@@ -763,6 +804,8 @@ public function defaultExposeOptions() {
$this->options['expose'] = [
'use_operator' => FALSE,
'operator' => $this->options['id'] . '_op',
'operator_limit_selection' => FALSE,
'operator_list' => [],
'identifier' => $this->options['id'],
'label' => $this->definition['title'],
'description' => NULL,
......@@ -848,6 +891,15 @@ public function buildExposedForm(&$form, FormStateInterface $form_state) {
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
$operator = $this->options['expose']['operator_id'];
$this->operatorForm($form, $form_state);
// Limit the exposed operators if needed.
if (!empty($this->options['expose']['operator_limit_selection']) &&
!empty($this->options['expose']['operator_list'])) {
$options = $this->operatorOptions();
$operator_list = $this->options['expose']['operator_list'];
$form['operator']['#options'] = array_intersect_key($options, $operator_list);
}
$form[$operator] = $form['operator'];
$this->exposedTranslate($form[$operator], 'operator');
......
......@@ -258,7 +258,23 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
}
}