diff options
Diffstat (limited to 'core/modules/views')
25 files changed, 493 insertions, 45 deletions
diff --git a/core/modules/views/config/schema/views.data_types.schema.yml b/core/modules/views/config/schema/views.data_types.schema.yml index 0e011d73dc15..31c6b2f6479e 100644 --- a/core/modules/views/config/schema/views.data_types.schema.yml +++ b/core/modules/views/config/schema/views.data_types.schema.yml @@ -633,29 +633,33 @@ views_pager: offset: type: integer label: 'Offset' + constraints: + PositiveOrZero: [] pagination_heading_level: + # Validating against a string, but the list is populated by a protected + # property of the plugin. This could be a callback in the future. type: string label: 'Pager header element' items_per_page: type: integer label: 'Items per page' + constraints: + PositiveOrZero: [] views_pager_sql: type: views_pager label: 'SQL pager' mapping: - items_per_page: - type: integer - label: 'Items per page' - pagination_heading_level: - type: string - label: 'Pager header element' total_pages: type: integer label: 'Number of pages' + constraints: + PositiveOrZero: [] id: type: integer label: 'Pager ID' + constraints: + PositiveOrZero: [] tags: type: mapping label: 'Pager link labels' @@ -669,6 +673,8 @@ views_pager_sql: quantity: type: integer label: 'Number of pager links visible' + constraints: + PositiveOrZero: [] expose: type: mapping label: 'Exposed options' @@ -682,6 +688,11 @@ views_pager_sql: items_per_page_options: type: string label: 'Exposed items per page options' + constraints: + # Comma separated list of integers, with optional space in between. + Regex: + pattern: '/^(\d+)(,\s*\d+)*$/' + message: 'Per page should be a valid list of integers.' items_per_page_options_all: type: boolean label: 'Include all items option' diff --git a/core/modules/views/config/schema/views.pager.schema.yml b/core/modules/views/config/schema/views.pager.schema.yml index eb360227e029..072dbc5b87e0 100644 --- a/core/modules/views/config/schema/views.pager.schema.yml +++ b/core/modules/views/config/schema/views.pager.schema.yml @@ -33,3 +33,5 @@ views.pager.full: quantity: type: integer label: 'Number of pager links visible' + constraints: + PositiveOrZero: [] diff --git a/core/modules/views/js/ajax_view.js b/core/modules/views/js/ajax_view.js index dd3da9b83507..8e646697d83e 100644 --- a/core/modules/views/js/ajax_view.js +++ b/core/modules/views/js/ajax_view.js @@ -83,7 +83,7 @@ if (queryString !== '') { // If there is a '?' in ajaxPath, clean URL are on and & should be // used to add parameters. - queryString = (/\?/.test(ajaxPath) ? '&' : '?') + queryString; + queryString = (ajaxPath.includes('?') ? '&' : '?') + queryString; } } diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php index cd1b2a0a42e1..f6bb32cec877 100644 --- a/core/modules/views/src/Entity/View.php +++ b/core/modules/views/src/Entity/View.php @@ -481,7 +481,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface { * {@inheritdoc} */ public function onDependencyRemoval(array $dependencies) { - $changed = FALSE; + $changed = parent::onDependencyRemoval($dependencies); // Don't intervene if the views module is removed. if (isset($dependencies['module']) && in_array('views', $dependencies['module'])) { diff --git a/core/modules/views/src/Form/ViewsExposedForm.php b/core/modules/views/src/Form/ViewsExposedForm.php index d68b1dd5363c..9f90160ff55f 100644 --- a/core/modules/views/src/Form/ViewsExposedForm.php +++ b/core/modules/views/src/Form/ViewsExposedForm.php @@ -196,7 +196,6 @@ class ViewsExposedForm extends FormBase implements WorkspaceSafeFormInterface { $view->exposed_data = $values; $view->exposed_raw_input = []; - $exclude = ['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 = $view->display_handler->getPlugin('exposed_form'); $exposed_form_plugin->exposedFormSubmit($form, $form_state, $exclude); diff --git a/core/modules/views/src/Plugin/views/argument/DayDate.php b/core/modules/views/src/Plugin/views/argument/DayDate.php index 884355a72a4b..a4a94da06998 100644 --- a/core/modules/views/src/Plugin/views/argument/DayDate.php +++ b/core/modules/views/src/Plugin/views/argument/DayDate.php @@ -29,7 +29,7 @@ class DayDate extends Date { $day = str_pad($data->{$this->name_alias}, 2, '0', STR_PAD_LEFT); // strtotime() respects server timezone, so we need to set the time fixed // as utc time - return $this->dateFormatter->format(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("200505" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } /** @@ -37,7 +37,7 @@ class DayDate extends Date { */ public function title() { $day = str_pad($this->argument, 2, '0', STR_PAD_LEFT); - return $this->dateFormatter->format(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("200505" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } /** diff --git a/core/modules/views/src/Plugin/views/argument/MonthDate.php b/core/modules/views/src/Plugin/views/argument/MonthDate.php index cec2159c9a3d..a24f23f120d9 100644 --- a/core/modules/views/src/Plugin/views/argument/MonthDate.php +++ b/core/modules/views/src/Plugin/views/argument/MonthDate.php @@ -28,7 +28,7 @@ class MonthDate extends Date { public function summaryName($data) { $month = str_pad($data->{$this->name_alias}, 2, '0', STR_PAD_LEFT); try { - return $this->dateFormatter->format(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("2005" . $month . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } catch (\InvalidArgumentException) { return parent::summaryName($data); @@ -41,7 +41,7 @@ class MonthDate extends Date { public function title() { $month = str_pad($this->argument, 2, '0', STR_PAD_LEFT); try { - return $this->dateFormatter->format(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("2005" . $month . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } catch (\InvalidArgumentException) { return parent::title(); diff --git a/core/modules/views/src/Plugin/views/argument/YearMonthDate.php b/core/modules/views/src/Plugin/views/argument/YearMonthDate.php index 16410ad25564..b82071f6d6ae 100644 --- a/core/modules/views/src/Plugin/views/argument/YearMonthDate.php +++ b/core/modules/views/src/Plugin/views/argument/YearMonthDate.php @@ -27,14 +27,14 @@ class YearMonthDate extends Date { */ public function summaryName($data) { $created = $data->{$this->name_alias}; - return $this->dateFormatter->format(strtotime($created . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime($created . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } /** * {@inheritdoc} */ public function title() { - return $this->dateFormatter->format(strtotime($this->argument . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime($this->argument . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } } diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index fc4a983f9299..d3adc61de5ab 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -2117,13 +2117,18 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte $hasMoreRecords = !empty($this->view->pager) && $this->view->pager->hasMoreRecords(); if ($this->isMoreEnabled() && ($this->useMoreAlways() || $hasMoreRecords)) { $url = $this->getMoreUrl(); + $access = $url->access(return_as_object: TRUE); - return [ + $more_link = [ '#type' => 'more_link', '#url' => $url, '#title' => $this->useMoreText(), '#view' => $this->view, + '#access' => $access->isAllowed(), ]; + $accessCacheability = CacheableMetadata::createFromObject($access); + $accessCacheability->applyTo($more_link); + return $more_link; } } diff --git a/core/modules/views/src/Plugin/views/pager/Full.php b/core/modules/views/src/Plugin/views/pager/Full.php index 0176fc6e7f90..ed8f7d7566a2 100644 --- a/core/modules/views/src/Plugin/views/pager/Full.php +++ b/core/modules/views/src/Plugin/views/pager/Full.php @@ -79,8 +79,8 @@ class Full extends SqlBase { * {@inheritdoc} */ public function render($input) { - // The 0, 1, 3, 4 indexes are correct. See the template_preprocess_pager() - // documentation. + // The 0, 1, 3, 4 indexes are correct. See the + // \Drupal\Core\Pager\PagerPreprocess::preprocessPager() documentation. $tags = [ 0 => $this->options['tags']['first'], 1 => $this->options['tags']['previous'], diff --git a/core/modules/views/src/Plugin/views/pager/Mini.php b/core/modules/views/src/Plugin/views/pager/Mini.php index 0f95f7a0d2f6..e17aa7fabdd7 100644 --- a/core/modules/views/src/Plugin/views/pager/Mini.php +++ b/core/modules/views/src/Plugin/views/pager/Mini.php @@ -90,7 +90,8 @@ class Mini extends SqlBase { * {@inheritdoc} */ public function render($input) { - // The 1, 3 indexes are correct, see template_preprocess_pager(). + // The 1, 3 indexes are correct, see + // \Drupal\Core\Pager\PagerPreprocess::preprocessPager(). $tags = [ 1 => $this->options['tags']['previous'], 3 => $this->options['tags']['next'], diff --git a/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php b/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php index 3356d703c93d..5796488746cc 100644 --- a/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php +++ b/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php @@ -29,14 +29,18 @@ abstract class PagerPluginBase extends PluginBase { /** * The current page. + * + * @phpcs:ignore Drupal.Commenting.VariableComment.MissingVar */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $current_page = NULL; /** * The total number of lines. + * + * @phpcs:ignore Drupal.Commenting.VariableComment.MissingVar */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $total_items = 0; /** diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php index 3f555cfec9fd..ca8df3ba8fef 100644 --- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php +++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php @@ -85,12 +85,12 @@ abstract class StylePluginBase extends PluginBase { /** * Stores the rendered field values, keyed by the row index and field name. * + * @var array|null + * * @see \Drupal\views\Plugin\views\style\StylePluginBase::renderFields() * @see \Drupal\views\Plugin\views\style\StylePluginBase::getField() - * - * @var array|null */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName protected $rendered_fields; /** diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php index 4867ba48f9a6..407260ed285d 100644 --- a/core/modules/views/src/ViewExecutable.php +++ b/core/modules/views/src/ViewExecutable.php @@ -400,21 +400,21 @@ class ViewExecutable { /** * Force the query to calculate the total number of results. * - * @todo Move to the query. - * * @var bool + * + * @todo Move to the query. */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $get_total_rows; /** * Indicates if the sorts have been built. * - * @todo Group with other static properties. - * * @var bool + * + * @todo Group with other static properties. */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $build_sort; /** diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_third_party_uninstall.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_third_party_uninstall.yml new file mode 100644 index 000000000000..eb59548f17f5 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_third_party_uninstall.yml @@ -0,0 +1,37 @@ +langcode: en +status: true +dependencies: + module: + - node + - views_third_party_settings_test +third_party_settings: + views_third_party_settings_test: + example_setting: true +id: test_third_party_uninstall +label: test_third_party_uninstall +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_options: + access: + type: none + cache: + type: tag + exposed_form: + type: basic + pager: + type: full + query: + type: views_query + style: + type: default + row: + type: fields + display_plugin: default + display_title: Defaults + id: default + position: 0 diff --git a/core/modules/views/tests/modules/views_test_data/test_views/views.view.test_content_access_filter.yml b/core/modules/views/tests/modules/views_test_data/test_views/views.view.test_content_access_filter.yml new file mode 100644 index 000000000000..8680489c2b6e --- /dev/null +++ b/core/modules/views/tests/modules/views_test_data/test_views/views.view.test_content_access_filter.yml @@ -0,0 +1,247 @@ +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + module: + - node + - user +id: test_content_access_filter +label: 'Test Content Access Filter' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_plugin: default + id: default + display_title: Default + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: default + row: + type: 'entity:node' + options: + view_mode: teaser + fields: + title: + id: title + table: node_field_data + field: title + entity_type: node + entity_field: title + label: '' + alter: + alter_text: false + make_link: false + absolute: false + trim: false + word_boundary: false + ellipsis: false + strip_tags: false + html: false + hide_empty: false + empty_zero: false + settings: + link_to_entity: true + plugin_id: field + relationship: none + group_type: group + admin_label: '' + exclude: 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_alter_empty: true + click_sort_column: value + type: string + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + filters: + nid: + id: nid + table: node_access + field: nid + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + 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: node_access + status: + id: status + table: node_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: node + entity_field: status + plugin_id: boolean + sorts: + created: + id: created + table: node_field_data + field: created + order: DESC + entity_type: node + entity_field: created + plugin_id: date + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + field_identifier: '' + granularity: second + title: 'Test Content Access Filter' + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + - 'user.node_grants:view' + - user.permissions + tags: { } + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: test-content-access-filter + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + - 'user.node_grants:view' + - user.permissions + tags: { } diff --git a/core/modules/views/tests/modules/views_third_party_settings_test/config/schema/views_third_party_settings_test.schema.yml b/core/modules/views/tests/modules/views_third_party_settings_test/config/schema/views_third_party_settings_test.schema.yml new file mode 100644 index 000000000000..0bdeeed705ab --- /dev/null +++ b/core/modules/views/tests/modules/views_third_party_settings_test/config/schema/views_third_party_settings_test.schema.yml @@ -0,0 +1,7 @@ +views.view.*.third_party.views_third_party_settings_test: + type: config_entity + label: "Example settings" + mapping: + example_setting: + type: boolean + label: "Example setting" diff --git a/core/modules/views/tests/modules/views_third_party_settings_test/views_third_party_settings_test.info.yml b/core/modules/views/tests/modules/views_third_party_settings_test/views_third_party_settings_test.info.yml new file mode 100644 index 000000000000..be9752795657 --- /dev/null +++ b/core/modules/views/tests/modules/views_third_party_settings_test/views_third_party_settings_test.info.yml @@ -0,0 +1,8 @@ +name: 'Third Party Settings Test' +type: module +description: 'A dummy module that third party settings tests can depend on' +package: Testing +version: VERSION +dependencies: + - drupal:node + - drupal:views diff --git a/core/modules/views/tests/src/Functional/GlossaryTest.php b/core/modules/views/tests/src/Functional/GlossaryTest.php index 292f91767715..25c08d5f1590 100644 --- a/core/modules/views/tests/src/Functional/GlossaryTest.php +++ b/core/modules/views/tests/src/Functional/GlossaryTest.php @@ -83,7 +83,6 @@ class GlossaryTest extends ViewTestBase { 'url', 'user.node_grants:view', 'user.permissions', - 'route', ], [ 'config:views.view.glossary', diff --git a/core/modules/views/tests/src/Functional/Plugin/AccessTest.php b/core/modules/views/tests/src/Functional/Plugin/AccessTest.php index df420cf879fa..92874dd8b417 100644 --- a/core/modules/views/tests/src/Functional/Plugin/AccessTest.php +++ b/core/modules/views/tests/src/Functional/Plugin/AccessTest.php @@ -22,7 +22,12 @@ class AccessTest extends ViewTestBase { * * @var array */ - public static $testViews = ['test_access_none', 'test_access_static', 'test_access_dynamic']; + public static $testViews = [ + 'test_access_none', + 'test_access_static', + 'test_access_dynamic', + 'test_content_access_filter', + ]; /** * {@inheritdoc} @@ -113,4 +118,32 @@ class AccessTest extends ViewTestBase { $this->assertSession()->statusCodeEquals(200); } + /** + * Tests that node_access table is joined when hook_node_grants() is implemented. + */ + public function testContentAccessFilter(): void { + $view = Views::getView('test_content_access_filter'); + $view->setDisplay('page_1'); + + $view->initQuery(); + $view->execute(); + /** @var \Drupal\Core\Database\Query\Select $main_query */ + $main_query = $view->build_info['query']; + $tables = array_keys($main_query->getTables()); + $this->assertNotContains('node_access', $tables); + + // Enable node access test module to ensure that table is present again. + \Drupal::service('module_installer')->install(['node_access_test']); + node_access_rebuild(); + + $view = Views::getView('test_content_access_filter'); + $view->setDisplay('page_1'); + $view->initQuery(); + $view->execute(); + /** @var \Drupal\Core\Database\Query\Select $main_query */ + $main_query = $view->build_info['query']; + $tables = array_keys($main_query->getTables()); + $this->assertContains('node_access', $tables); + } + } diff --git a/core/modules/views/tests/src/Functional/Plugin/DisplayTest.php b/core/modules/views/tests/src/Functional/Plugin/DisplayTest.php index 8af887d1ef1b..5aecbea3e366 100644 --- a/core/modules/views/tests/src/Functional/Plugin/DisplayTest.php +++ b/core/modules/views/tests/src/Functional/Plugin/DisplayTest.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Drupal\Tests\views\Functional\Plugin; -use Drupal\Component\Render\FormattableMarkup; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\Tests\views\Functional\ViewTestBase; use Drupal\views\Views; @@ -317,6 +316,14 @@ class DisplayTest extends ViewTestBase { $output = $view->preview(); $output = (string) $renderer->renderRoot($output); $this->assertStringContainsString('/node?date=22&foo=bar#22', $output, 'The read more link with href "/node?date=22&foo=bar#22" was found.'); + + // Test more link isn't rendered if user doesn't have permission to the + // more link URL. + $view->display_handler->setOption('link_url', 'admin/content'); + $this->executeView($view); + $output = $view->preview(); + $output = (string) $renderer->renderRoot($output); + $this->assertStringNotContainsString('/admin/content', $output, 'The read more link with href "/admin/content" was not found.'); } /** @@ -389,8 +396,8 @@ class DisplayTest extends ViewTestBase { $errors = $view->validate(); // Check that the error messages are shown. $this->assertCount(2, $errors['default'], 'Error messages found for required relationship'); - $this->assertEquals(new FormattableMarkup('The %relationship_name relationship used in %handler_type %handler is not present in the %display_name display.', ['%relationship_name' => 'uid', '%handler_type' => 'field', '%handler' => 'User: Last login', '%display_name' => 'Default']), $errors['default'][0]); - $this->assertEquals(new FormattableMarkup('The %relationship_name relationship used in %handler_type %handler is not present in the %display_name display.', ['%relationship_name' => 'uid', '%handler_type' => 'field', '%handler' => 'User: Created', '%display_name' => 'Default']), $errors['default'][1]); + $this->assertEquals("The uid relationship used in field User: Last login is not present in the Default display.", $errors['default'][0]); + $this->assertEquals("The uid relationship used in field User: Created is not present in the Default display.", $errors['default'][1]); } /** diff --git a/core/modules/views/tests/src/Kernel/Handler/ArgumentSummaryTest.php b/core/modules/views/tests/src/Kernel/Handler/ArgumentSummaryTest.php index 03488125064a..e19f1414615f 100644 --- a/core/modules/views/tests/src/Kernel/Handler/ArgumentSummaryTest.php +++ b/core/modules/views/tests/src/Kernel/Handler/ArgumentSummaryTest.php @@ -150,4 +150,38 @@ class ArgumentSummaryTest extends ViewsKernelTestBase { $this->assertStringContainsString($tags[1]->label() . ' (2)', $output); } + /** + * Tests that the active link is set correctly. + */ + public function testActiveLink(): void { + require_once $this->root . '/core/modules/views/views.theme.inc'; + + // We need at least one node. + Node::create([ + 'type' => $this->nodeType->id(), + 'title' => $this->randomMachineName(), + ])->save(); + + $view = Views::getView('test_argument_summary'); + $view->execute(); + $view->build(); + $variables = [ + 'view' => $view, + 'rows' => $view->result, + ]; + + template_preprocess_views_view_summary_unformatted($variables); + $this->assertFalse($variables['rows'][0]->active); + + template_preprocess_views_view_summary($variables); + $this->assertFalse($variables['rows'][0]->active); + + // Checks that the row with the current path is active. + \Drupal::service('path.current')->setPath('/test-argument-summary'); + template_preprocess_views_view_summary_unformatted($variables); + $this->assertTrue($variables['rows'][0]->active); + template_preprocess_views_view_summary($variables); + $this->assertTrue($variables['rows'][0]->active); + } + } diff --git a/core/modules/views/tests/src/Kernel/Plugin/ExposedFormRenderTest.php b/core/modules/views/tests/src/Kernel/Plugin/ExposedFormRenderTest.php index 97d670634b3f..14f90fd0c33a 100644 --- a/core/modules/views/tests/src/Kernel/Plugin/ExposedFormRenderTest.php +++ b/core/modules/views/tests/src/Kernel/Plugin/ExposedFormRenderTest.php @@ -137,12 +137,13 @@ class ExposedFormRenderTest extends ViewsKernelTestBase { $view->save(); $this->executeView($view); + // The "type" filter should be excluded from the raw input because its + // value is "All". $expected = [ - 'type' => 'All', 'type_with_default_value' => 'article', 'multiple_types_with_default_value' => ['article' => 'article'], ]; - $this->assertSame($view->exposed_raw_input, $expected); + $this->assertSame($expected, $view->exposed_raw_input); } } diff --git a/core/modules/views/tests/src/Kernel/ThirdPartyUninstallTest.php b/core/modules/views/tests/src/Kernel/ThirdPartyUninstallTest.php new file mode 100644 index 000000000000..0f3d3eb5291a --- /dev/null +++ b/core/modules/views/tests/src/Kernel/ThirdPartyUninstallTest.php @@ -0,0 +1,55 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\views\Kernel; + +use Drupal\views\Entity\View; + +/** + * Tests proper removal of third-party settings from views. + * + * @group views + */ +class ThirdPartyUninstallTest extends ViewsKernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['node', 'views_third_party_settings_test']; + + /** + * Views used by this test. + * + * @var array + */ + public static $testViews = ['test_third_party_uninstall']; + + /** + * {@inheritdoc} + */ + protected function setUp($import_test_views = TRUE): void { + parent::setUp($import_test_views); + + $this->installEntitySchema('user'); + $this->installSchema('user', ['users_data']); + } + + /** + * Tests removing third-party settings when a provider module is uninstalled. + */ + public function testThirdPartyUninstall(): void { + $view = View::load('test_third_party_uninstall'); + $this->assertNotEmpty($view); + $this->assertContains('views_third_party_settings_test', $view->getDependencies()['module']); + $this->assertTrue($view->getThirdPartySetting('views_third_party_settings_test', 'example_setting')); + + \Drupal::service('module_installer')->uninstall(['views_third_party_settings_test']); + + $view = View::load('test_third_party_uninstall'); + $this->assertNotEmpty($view); + $this->assertNotContains('views_third_party_settings_test', $view->getDependencies()['module']); + $this->assertNull($view->getThirdPartySetting('views_third_party_settings_test', 'example_setting')); + } + +} diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc index 10c29c5dbf30..04c5de5a535f 100644 --- a/core/modules/views/views.theme.inc +++ b/core/modules/views/views.theme.inc @@ -253,15 +253,12 @@ function template_preprocess_views_view_summary(&$variables): void { $url_options['query'] = $view->exposed_raw_input; } + $currentPath = \Drupal::service('path.current')->getPath(); $active_urls = [ // Force system path. - Url::fromRoute('<current>', [], ['alias' => TRUE])->toString(), - // Force system path. - Url::fromRouteMatch(\Drupal::routeMatch())->setOption('alias', TRUE)->toString(), - // Could be an alias. - Url::fromRoute('<current>')->toString(), + Url::fromUserInput($currentPath, ['alias' => TRUE])->toString(), // Could be an alias. - Url::fromRouteMatch(\Drupal::routeMatch())->toString(), + Url::fromUserInput($currentPath)->toString(), ]; $active_urls = array_combine($active_urls, $active_urls); @@ -342,11 +339,12 @@ function template_preprocess_views_view_summary_unformatted(&$variables): void { } $count = 0; + $currentPath = \Drupal::service('path.current')->getPath(); $active_urls = [ // Force system path. - Url::fromRoute('<current>', [], ['alias' => TRUE])->toString(), + Url::fromUserInput($currentPath, ['alias' => TRUE])->toString(), // Could be an alias. - Url::fromRoute('<current>')->toString(), + Url::fromUserInput($currentPath)->toString(), ]; $active_urls = array_combine($active_urls, $active_urls); |