Skip to content

Instantly share code, notes, and snippets.

@edwardchan
Created April 20, 2017 17:12
Show Gist options
  • Save edwardchan/5acb6d3d00fbcb521c55b1ae1dedfed6 to your computer and use it in GitHub Desktop.
Save edwardchan/5acb6d3d00fbcb521c55b1ae1dedfed6 to your computer and use it in GitHub Desktop.
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
index a68c3c8..cd89b77 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
@@ -6,6 +6,7 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\TermStorageInterface;
+use Drupal\taxonomy\VocabularyInterface;
use Drupal\taxonomy\VocabularyStorageInterface;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -78,11 +79,16 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
parent::init($view, $display, $options);
if (!empty($this->definition['vocabulary'])) {
- $this->options['vid'] = $this->definition['vocabulary'];
+ $this->options['vids'] = [$this->definition['vocabulary']];
+ }
+ if (empty($this->options['vids']) && !empty($this->options['vid'])) {
+ $this->options['vids'] = [$this->options['vid']];
}
}
- public function hasExtraOptions() { return TRUE; }
+ public function hasExtraOptions() {
+ return TRUE;
+ }
/**
* {@inheritdoc}
@@ -96,13 +102,16 @@ protected function defineOptions() {
$options['type'] = ['default' => 'textfield'];
$options['limit'] = ['default' => TRUE];
- $options['vid'] = ['default' => ''];
+ $options['vids'] = ['default' => []];
$options['hierarchy'] = ['default' => FALSE];
$options['error_message'] = ['default' => TRUE];
return $options;
}
+ /**
+ * {@inheritdoc}
+ */
public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
$vocabularies = $this->vocabularyStorage->loadMultiple();
$options = [];
@@ -112,18 +121,19 @@ public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
if ($this->options['limit']) {
// We only do this when the form is displayed.
- if (empty($this->options['vid'])) {
+ if (empty($this->options['vids'])) {
$first_vocabulary = reset($vocabularies);
- $this->options['vid'] = $first_vocabulary->id();
+ $this->options['vids'] = $first_vocabulary->id();
}
if (empty($this->definition['vocabulary'])) {
- $form['vid'] = [
- '#type' => 'radios',
+ $form['vids'] = [
+ '#type' => 'checkboxes',
'#title' => $this->t('Vocabulary'),
'#options' => $options,
'#description' => $this->t('Select which vocabulary to show terms for in the regular options.'),
- '#default_value' => $this->options['vid'],
+ '#default_value' => $this->options['vids'],
+ '#required' => TRUE,
];
}
}
@@ -131,7 +141,10 @@ public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
$form['type'] = [
'#type' => 'radios',
'#title' => $this->t('Selection type'),
- '#options' => ['select' => $this->t('Dropdown'), 'textfield' => $this->t('Autocomplete')],
+ '#options' => [
+ 'select' => $this->t('Dropdown'),
+ 'textfield' => $this->t('Autocomplete')
+ ],
'#default_value' => $this->options['type'],
];
@@ -147,9 +160,32 @@ public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
];
}
+ /**
+ * {@inheritdoc}
+ */
+ public function validateExtraOptionsForm($form, FormStateInterface $form_state) {
+ parent::validateExtraOptionsForm($form, $form_state);
+
+ // Don't allow to select more than one vocabulary when 'select' is chosen.
+ $vids = $form_state->getValue(['options', 'vids']);
+ $selection_type = $form_state->getValue(['options', 'type']);
+ if ($selection_type === 'select' && count($vids) > 1) {
+ $form_state->setErrorByName('options][vids', $this->t("You cannot select more than one vocabulary, when choosing 'Dropdown' as selection type."));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitExtraOptionsForm($form, FormStateInterface $form_state) {
+ $vids = $form_state->getValue(['options', 'vids']);
+ $form_state->setValue(['options', 'vids'], array_keys(array_filter($vids)));
+ }
+
protected function valueForm(&$form, FormStateInterface $form_state) {
- $vocabulary = $this->vocabularyStorage->load($this->options['vid']);
- if (empty($vocabulary) && $this->options['limit']) {
+ $vocabularies = $this->vocabularyStorage->loadMultiple($this->options['vids']);
+ $vocabulary = reset($vocabularies);
+ if (empty($vocabularies) && $this->options['limit']) {
$form['markup'] = [
'#markup' => '<div class="js-form-item form-item">' . $this->t('An invalid vocabulary is selected. Please change it in the options.') . '</div>',
];
@@ -158,8 +194,11 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
if ($this->options['type'] == 'textfield') {
$terms = $this->value ? Term::loadMultiple(($this->value)) : [];
+ $vocabulary_labels = array_map(function (VocabularyInterface $vocabulary) {
+ return $vocabulary->label();
+ }, $vocabularies);
$form['value'] = [
- '#title' => $this->options['limit'] ? $this->t('Select terms from vocabulary @voc', ['@voc' => $vocabulary->label()]) : $this->t('Select terms'),
+ '#title' => $this->options['limit'] ? $this->t('Select terms from vocabularies @vocs', array('@vocs' => implode(', ', $vocabulary_labels))) : $this->t('Select terms'),
'#type' => 'textfield',
'#default_value' => EntityAutocomplete::getEntityLabels($terms),
];
@@ -167,7 +206,7 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
if ($this->options['limit']) {
$form['value']['#type'] = 'entity_autocomplete';
$form['value']['#target_type'] = 'taxonomy_term';
- $form['value']['#selection_settings']['target_bundles'] = [$vocabulary->id()];
+ $form['value']['#selection_settings']['target_bundles'] = array_keys($vocabularies);
$form['value']['#tags'] = TRUE;
$form['value']['#process_default_value'] = FALSE;
}
@@ -180,7 +219,11 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
if ($tree) {
foreach ($tree as $term) {
$choice = new \stdClass();
- $choice->option = [$term->id() => str_repeat('-', $term->depth) . \Drupal::entityManager()->getTranslationFromContext($term)->label()];
+ $choice->option = [
+ $term->id() => str_repeat('-', $term->depth) . \Drupal::entityManager()
+ ->getTranslationFromContext($term)
+ ->label()
+ ];
$options[] = $choice;
}
}
@@ -198,7 +241,9 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
}
$terms = Term::loadMultiple($query->execute());
foreach ($terms as $term) {
- $options[$term->id()] = \Drupal::entityManager()->getTranslationFromContext($term)->label();
+ $options[$term->id()] = \Drupal::entityManager()
+ ->getTranslationFromContext($term)
+ ->label();
}
}
@@ -363,7 +408,9 @@ public function adminSummary() {
$this->value = array_filter($this->value);
$terms = Term::loadMultiple($this->value);
foreach ($terms as $term) {
- $this->valueOptions[$term->id()] = \Drupal::entityManager()->getTranslationFromContext($term)->label();
+ $this->valueOptions[$term->id()] = \Drupal::entityManager()
+ ->getTranslationFromContext($term)
+ ->label();
}
}
return parent::adminSummary();
@@ -387,9 +434,10 @@ public function getCacheContexts() {
*/
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
-
- $vocabulary = $this->vocabularyStorage->load($this->options['vid']);
- $dependencies[$vocabulary->getConfigDependencyKey()][] = $vocabulary->getConfigDependencyName();
+ $vocabularies = $this->vocabularyStorage->loadMultiple($this->options['vids']);
+ foreach ($vocabularies as $vocabulary) {
+ $dependencies[$vocabulary->getConfigDependencyKey()][] = $vocabulary->getConfigDependencyName();
+ }
foreach ($this->termStorage->loadMultiple($this->options['value']) as $term) {
$dependencies[$term->getConfigDependencyKey()][] = $term->getConfigDependencyName();
diff --git a/core/modules/taxonomy/src/Tests/Views/TaxonomyIndexTidUiTest.php b/core/modules/taxonomy/src/Tests/Views/TaxonomyIndexTidUiTest.php
index efa5191..d89fd79 100644
--- a/core/modules/taxonomy/src/Tests/Views/TaxonomyIndexTidUiTest.php
+++ b/core/modules/taxonomy/src/Tests/Views/TaxonomyIndexTidUiTest.php
@@ -3,6 +3,7 @@
namespace Drupal\taxonomy\Tests\Views;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
+use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\views\Tests\ViewTestData;
@@ -24,14 +25,23 @@ class TaxonomyIndexTidUiTest extends UITestBase {
*
* @var array
*/
- public static $testViews = ['test_filter_taxonomy_index_tid', 'test_taxonomy_term_name'];
+ public static $testViews = [
+ 'test_filter_taxonomy_index_tid',
+ 'test_taxonomy_term_name'
+ ];
/**
* Modules to enable.
*
* @var array
*/
- public static $modules = ['node', 'taxonomy', 'views', 'views_ui', 'taxonomy_test_views'];
+ public static $modules = [
+ 'node',
+ 'taxonomy',
+ 'views',
+ 'views_ui',
+ 'taxonomy_test_views'
+ ];
/**
* A nested array of \Drupal\taxonomy\TermInterface objects.
@@ -46,13 +56,30 @@ class TaxonomyIndexTidUiTest extends UITestBase {
protected function setUp() {
parent::setUp();
- $this->adminUser = $this->drupalCreateUser(['administer taxonomy', 'administer views']);
+ $this->adminUser = $this->drupalCreateUser([
+ 'administer taxonomy',
+ 'administer views'
+ ]);
$this->drupalLogin($this->adminUser);
+ $this->terms = $this->createVocabularyAndTerms('tags');
+ ViewTestData::createTestViews(get_class($this), array('taxonomy_test_views'));
+
Vocabulary::create([
- 'vid' => 'tags',
- 'name' => 'Tags',
+ 'vid' => 'empty_vocabulary',
+ 'name' => 'Empty Vocabulary',
])->save();
+ }
+
+ /**
+ * Creates a vocabulary and terms for it.
+ *
+ * @param string $vocab_id
+ * The vocabulary ID.
+ *
+ * @return \Drupal\taxonomy\TermInterface[][]
+ */
+ protected function createVocabularyAndTerms($vocab_id) {
// Setup a hierarchy which looks like this:
// term 0.0
@@ -61,22 +88,19 @@ protected function setUp() {
// term 2.0
// - term 2.1
// - term 2.2
+ $terms = [];
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j <= $i; $j++) {
- $this->terms[$i][$j] = $term = Term::create([
- 'vid' => 'tags',
+ $terms[$i][$j] = $term = Term::create([
+ 'vid' => $vocab_id,
'name' => "Term $i.$j",
'parent' => isset($terms[$i][0]) ? $terms[$i][0]->id() : 0,
]);
$term->save();
}
}
- ViewTestData::createTestViews(get_class($this), ['taxonomy_test_views']);
- Vocabulary::create([
- 'vid' => 'empty_vocabulary',
- 'name' => 'Empty Vocabulary',
- ])->save();
+ return $terms;
}
/**
@@ -124,7 +148,93 @@ public function testFilterUI() {
'user',
],
];
- $this->assertIdentical($expected, $view->calculateDependencies()->getDependencies());
+ $this->assertIdentical($expected, $view->calculateDependencies()
+ ->getDependencies());
+ }
+
+ public function testFilterUIWithMoreVocabularies() {
+ $terms2 = $this->createVocabularyAndTerms('tags2');
+
+ $node_type = $this->drupalCreateContentType(['type' => 'page']);
+
+ // Create the tag field itself.
+ $field_name = 'taxonomy_tags';
+ $this->createEntityReferenceField('node', $node_type->id(), $field_name, NULL, 'taxonomy_term');
+
+ $node0 = $this->drupalCreateNode([
+ 'type' => 'page',
+ 'taxonomy_tags' => $this->terms[0][0]->id(),
+ ]);
+ $node0->save();
+ $node1 = $this->drupalCreateNode([
+ 'type' => 'page',
+ 'taxonomy_tags' => $terms2[0][0]->id(),
+ ]);
+ $node1->save();
+ $node2 = $this->drupalCreateNode([
+ 'type' => 'page',
+ 'taxonomy_tags' => [$this->terms[0][0]->id(), $terms2[0][0]->id()],
+ ]);
+ $node2->save();
+
+ $edit = [
+ 'options[vids][tags]' => TRUE,
+ 'options[vids][tags2]' => TRUE,
+ 'options[type]' => 'select',
+ ];
+ $this->drupalPostForm('admin/structure/views/nojs/handler-extra/test_filter_taxonomy_index_tid/default/filter/tid', $edit, 'Apply');
+ $this->assertText("You cannot select more than one vocabulary, when choosing 'Dropdown' as selection type.");
+
+ $edit = [
+ 'options[vids][tags]' => TRUE,
+ 'options[vids][tags2]' => TRUE,
+ 'options[type]' => 'textfield',
+ ];
+ $this->drupalPostForm('admin/structure/views/nojs/handler-extra/test_filter_taxonomy_index_tid/default/filter/tid', $edit, 'Apply');
+ $this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid', [], 'Expose filter');
+ $edit = [
+ 'options[operator]' => 'and',
+ 'options[value]' => '',
+ 'options[reduce_duplicates]' => TRUE
+ ];
+ $this->drupalPostForm(NULL, $edit, 'Apply');
+ $this->drupalPostForm(NULL, [], 'Save');
+
+ $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => '']]);
+ $xpath = $this->xpath('//div[@class="view-content"]//a');
+ $this->assertIdentical(3, count($xpath));
+
+ $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => "t1 ({$this->terms[0][0]->id()})"]]);
+ $xpath = $this->xpath('//div[@class="view-content"]//a');
+ $this->assertIdentical(2, count($xpath));
+ $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [
+ ':href' => $node0->toUrl()->toString()
+ ]);
+ $this->assertIdentical(1, count($xpath));
+ $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [
+ ':href' => $node2->toUrl()->toString()
+ ]);
+ $this->assertIdentical(1, count($xpath));
+
+ $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => "t2 ({$terms2[0][0]->id()})"]]);
+ $xpath = $this->xpath('//div[@class="view-content"]//a');
+ $this->assertIdentical(2, count($xpath));
+ $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [
+ ':href' => $node1->toUrl()->toString()
+ ]);
+ $this->assertIdentical(1, count($xpath));
+ $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [
+ ':href' => $node2->toUrl()->toString()
+ ]);
+ $this->assertIdentical(1, count($xpath));
+
+ $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => "t1 ({$this->terms[0][0]->id()}), t2 ({$terms2[0][0]->id()})"]]);
+ $xpath = $this->xpath('//div[@class="view-content"]//a');
+ $this->assertIdentical(1, count($xpath));
+ $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [
+ ':href' => $node2->toUrl()->toString()
+ ]);
+ $this->assertIdentical(1, count($xpath));
}
/**
diff --git a/core/modules/taxonomy/taxonomy.post_update.php b/core/modules/taxonomy/taxonomy.post_update.php
index e69de29..ed7cb4a 100644
--- a/core/modules/taxonomy/taxonomy.post_update.php
+++ b/core/modules/taxonomy/taxonomy.post_update.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @addtogroup updates-8.3.0
+ * @{
+ */
+
+/**
+ * Update views using taxonomy_index_tid to use vids instead of vid.
+ */
+function taxonomy_post_update_taxonomy_index_filter_multiple_vocabularies() {
+ // Load all views.
+ $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
+
+ /* @var \Drupal\views\Entity\View[] $views */
+ foreach ($views as $view) {
+ $save = FALSE;
+ $displays = $view->get('display');
+ foreach (array_keys($displays) as $display_id) {
+ $display =& $view->getDisplay($display_id);
+ if (!empty($display['display_options']['filters'])) {
+ foreach ($display['display_options']['filters'] as &$filter) {
+ if ($filter['plugin_id'] === 'taxonomy_index_tid' && empty($filter['vids']) && !empty($filter['vid'])) {
+ $filter['vids'] = [$filter['vid']];
+ unset($filter['vid']);
+ $save = TRUE;
+ }
+ }
+ }
+ }
+ if ($save) {
+ $view->save();
+ }
+ }
+}
+
+/**
+ * @} End of "addtogroup updates-8.3.0
+ */
diff --git a/core/modules/taxonomy/tests/fixtures/update/taxonomy-index-filter-multiple-vocabularies.php b/core/modules/taxonomy/tests/fixtures/update/taxonomy-index-filter-multiple-vocabularies.php
index e69de29..b4c8bb7 100644
--- a/core/modules/taxonomy/tests/fixtures/update/taxonomy-index-filter-multiple-vocabularies.php
+++ b/core/modules/taxonomy/tests/fixtures/update/taxonomy-index-filter-multiple-vocabularies.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Test fixture.
+ */
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Serialization\Yaml;
+
+$connection = Database::getConnection();
+
+$connection->insert('config')
+ ->fields(array(
+ 'collection' => '',
+ 'name' => 'views.view.test_filter_taxonomy_index_tid_pre_update',
+ 'data' => serialize(Yaml::decode(file_get_contents('core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_pre_update.yml'))),
+ ))
+ ->execute();
\ No newline at end of file
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml
index ab5e1d8..ed6f358 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml
@@ -166,7 +166,8 @@ display:
reduce_duplicates: false
type: select
limit: true
- vid: tags
+ vids:
+ - tags
hierarchy: true
error_message: true
plugin_id: taxonomy_index_tid
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml
index a5c5828..0fe8db8 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml
@@ -167,7 +167,8 @@ display:
reduce_duplicates: false
type: select
limit: true
- vid: tags
+ vids:
+ - tags
hierarchy: true
error_message: true
plugin_id: taxonomy_index_tid
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml
index 856543a..0ca41c9 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml
@@ -165,7 +165,8 @@ display:
reduce_duplicates: false
type: select
limit: true
- vid: views_testing_tags
+ vids:
+ - views_testing_tags
hierarchy: true
depth: -2
error_message: true
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index f9bd098..d82cd75 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -13,6 +13,7 @@
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\views\Plugin\Derivative\ViewsLocalTask;
+use Drupal\views\ViewEntityInterface;
use Drupal\views\ViewExecutable;
use Drupal\views\Entity\View;
use Drupal\views\Render\ViewsRenderPipelineMarkup;
@@ -29,7 +30,10 @@ function views_help($route_name, RouteMatchInterface $route_match) {
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Views module provides a back end to fetch information from content, user accounts, taxonomy terms, and other entities from the database and present it to the user as a grid, HTML list, table, unformatted list, etc. The resulting displays are known generally as <em>views</em>.') . '</p>';
$output .= '<p>' . t('For more information, see the <a href=":views">online documentation for the Views module</a>.', [':views' => 'https://www.drupal.org/documentation/modules/views']) . '</p>';
- $output .= '<p>' . t('In order to create and modify your own views using the administration and configuration user interface, you will need to enable either the Views UI module in core or a contributed module that provides a user interface for Views. See the <a href=":views-ui">Views UI module help page</a> for more information.', [':views-ui' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('help.page', ['name' => 'views_ui']) : '#']) . '</p>';
+ $output .= '<p>' . t('In order to create and modify your own views using the administration and configuration user interface, you will need to enable either the Views UI module in core or a contributed module that provides a user interface for Views. See the <a href=":views-ui">Views UI module help page</a> for more information.', [
+ ':views-ui' => (\Drupal::moduleHandler()
+ ->moduleExists('views_ui')) ? \Drupal::url('help.page', ['name' => 'views_ui']) : '#'
+ ]) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Adding functionality to administrative pages') . '</dt>';
@@ -91,8 +95,13 @@ function views_theme($existing, $type, $theme, $path) {
// Our extra version of pager from pager.inc
$hooks['views_mini_pager'] = $base + [
- 'variables' => ['tags' => [], 'quantity' => 9, 'element' => 0, 'parameters' => []],
- ];
+ 'variables' => [
+ 'tags' => [],
+ 'quantity' => 9,
+ 'element' => 0,
+ 'parameters' => []
+ ],
+ ];
$variables = [
// For displays, we pass in a dummy array as the first parameter, since
@@ -113,22 +122,42 @@ function views_theme($existing, $type, $theme, $path) {
'attachment_before' => [],
'attachment_after' => [],
],
- 'style' => ['view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL],
- 'row' => ['view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL],
+ 'style' => [
+ 'view' => NULL,
+ 'options' => NULL,
+ 'rows' => NULL,
+ 'title' => NULL
+ ],
+ 'row' => [
+ 'view' => NULL,
+ 'options' => NULL,
+ 'row' => NULL,
+ 'field_alias' => NULL
+ ],
'exposed_form' => ['view' => NULL, 'options' => NULL],
'pager' => [
- 'view' => NULL, 'options' => NULL,
- 'tags' => [], 'quantity' => 9, 'element' => 0, 'parameters' => []
+ 'view' => NULL,
+ 'options' => NULL,
+ 'tags' => [],
+ 'quantity' => 9,
+ 'element' => 0,
+ 'parameters' => []
],
];
// Default view themes
$hooks['views_view_field'] = $base + [
- 'variables' => ['view' => NULL, 'field' => NULL, 'row' => NULL],
- ];
+ 'variables' => ['view' => NULL, 'field' => NULL, 'row' => NULL],
+ ];
$hooks['views_view_grouping'] = $base + [
- 'variables' => ['view' => NULL, 'grouping' => NULL, 'grouping_level' => NULL, 'rows' => NULL, 'title' => NULL],
- ];
+ 'variables' => [
+ 'view' => NULL,
+ 'grouping' => NULL,
+ 'grouping_level' => NULL,
+ 'rows' => NULL,
+ 'title' => NULL
+ ],
+ ];
// Only display, pager, row, and style plugins can provide theme hooks.
$plugin_types = [
@@ -140,7 +169,8 @@ function views_theme($existing, $type, $theme, $path) {
];
$plugins = [];
foreach ($plugin_types as $plugin_type) {
- $plugins[$plugin_type] = Views::pluginManager($plugin_type)->getDefinitions();
+ $plugins[$plugin_type] = Views::pluginManager($plugin_type)
+ ->getDefinitions();
}
$module_handler = \Drupal::moduleHandler();
@@ -211,12 +241,12 @@ function views_theme($existing, $type, $theme, $path) {
}
$hooks['views_form_views_form'] = $base + [
- 'render element' => 'form',
- ];
+ 'render element' => 'form',
+ ];
$hooks['views_exposed_form'] = $base + [
- 'render element' => 'form',
- ];
+ 'render element' => 'form',
+ ];
return $hooks;
}
@@ -237,9 +267,10 @@ function views_preprocess_node(&$variables) {
// If a node is being rendered in a view, and the view does not have a path,
// prevent drupal from accidentally setting the $page variable:
if (!empty($variables['view']->current_display)
- && $variables['page']
- && $variables['view_mode'] == 'full'
- && !$variables['view']->display_handler->hasPath()) {
+ && $variables['page']
+ && $variables['view_mode'] == 'full'
+ && !$variables['view']->display_handler->hasPath()
+ ) {
$variables['page'] = FALSE;
}
}
@@ -361,18 +392,25 @@ function views_add_contextual_links(&$render_element, $location, $display_id, ar
if (!isset($view_element)) {
$view_element = $render_element;
}
- $view_element['#cache_properties'] = ['view_id', 'view_display_show_admin_links', 'view_display_plugin_id'];
+ $view_element['#cache_properties'] = [
+ 'view_id',
+ 'view_display_show_admin_links',
+ 'view_display_plugin_id'
+ ];
$view_id = $view_element['#view_id'];
$show_admin_links = $view_element['#view_display_show_admin_links'];
$display_plugin_id = $view_element['#view_display_plugin_id'];
// Do not do anything if the view is configured to hide its administrative
// links or if the Contextual Links module is not enabled.
- if (\Drupal::moduleHandler()->moduleExists('contextual') && $show_admin_links) {
+ if (\Drupal::moduleHandler()
+ ->moduleExists('contextual') && $show_admin_links
+ ) {
// Also do not do anything if the display plugin has not defined any
// contextual links that are intended to be displayed in the requested
// location.
- $plugin = Views::pluginManager('display')->getDefinition($display_plugin_id);
+ $plugin = Views::pluginManager('display')
+ ->getDefinition($display_plugin_id);
// If contextual_links_locations are not set, provide a sane default. (To
// avoid displaying any contextual links at all, a display plugin can still
// set 'contextual_links_locations' to, e.g., {""}.)
@@ -617,7 +655,8 @@ function views_pre_render_views_form_views_form($element) {
$replace[] = isset($element[$field_name][$row_id]) ? drupal_render($element[$field_name][$row_id]) : '';
}
// Add in substitutions from hook_views_form_substitutions().
- $substitutions = \Drupal::moduleHandler()->invokeAll('views_form_substitutions');
+ $substitutions = \Drupal::moduleHandler()
+ ->invokeAll('views_form_substitutions');
foreach ($substitutions as $placeholder => $substitution) {
$search[] = Html::escape($placeholder);
// Ensure that any replacements made are safe to make.
@@ -828,3 +867,30 @@ function views_view_delete(EntityInterface $entity) {
}
}
}
+
+/**
+ * Implements hook_view_presave().
+ *
+ * Provides a BC layer for modules providing old configurations.
+ */
+function views_view_presave(ViewEntityInterface $view) {
+ foreach ($view->get('display') as $display_name => $display) {
+ if (isset($display['display_options']['filters'])) {
+ foreach ($display['display_options']['filters'] as $filter_name => $filter) {
+ if (isset($filter['plugin_id']) && $filter['plugin_id'] === 'boolean') {
+ $new_value = FALSE;
+ // Update all boolean and integer values to strings.
+ if ($filter['value'] === TRUE || $filter['value'] === 1) {
+ $new_value = '1';
+ }
+ elseif ($filter['value'] === FALSE || $filter['value'] === 0) {
+ $new_value = '0';
+ }
+ if ($new_value !== FALSE) {
+ $view->set("display.$display_name.display_options.filters.$filter_name.value", $new_value);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php
index a79d031..36f2df3 100644
--- a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php
+++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php
@@ -93,6 +93,10 @@ public function buildForm(array $form, FormStateInterface $form_state) {
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$form_state->get('handler')->validateExtraOptionsForm($form['options'], $form_state);
+
+ if ($form_state->getErrors()) {
+ $form_state->set('rerender', TRUE);
+ }
}
/**
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment