diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 624e10e46abdd281b661e9635ac054c7465ec158..8c164c6b8a58e2f45169764403137d97be72ed58 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -2447,6 +2447,16 @@ public function validate() { $errors = array_merge($errors, $result); } + // Check for missing relationships. + $relationships = array_keys($this->getHandlers('relationship')); + foreach (ViewExecutable::getHandlerTypes() as $type => $handler_type_info) { + foreach ($this->getHandlers($type) as $handler_id => $handler) { + if (!empty($handler->options['relationship']) && $handler->options['relationship'] != 'none' && !in_array($handler->options['relationship'], $relationships)) { + $errors[] = $this->t('The %handler_type %handler uses a relationship that has been removed.', array('%handler_type' => $handler_type_info['lstitle'], '%handler' => $handler->adminLabel())); + } + } + } + // Validate handlers. foreach (ViewExecutable::getHandlerTypes() as $type => $info) { foreach ($this->getHandlers($type) as $handler) { diff --git a/core/modules/views/src/Tests/Plugin/DisplayTest.php b/core/modules/views/src/Tests/Plugin/DisplayTest.php index 66266207c80cf9ebe74c8aa1d78415601417f5ac..be003cf9e5933ec57d19db7be03c5e44cd421e7c 100644 --- a/core/modules/views/src/Tests/Plugin/DisplayTest.php +++ b/core/modules/views/src/Tests/Plugin/DisplayTest.php @@ -24,7 +24,7 @@ class DisplayTest extends PluginTestBase { * * @var array */ - public static $testViews = array('test_filter_groups', 'test_get_attach_displays', 'test_view', 'test_display_more', 'test_display_invalid', 'test_display_empty'); + public static $testViews = array('test_filter_groups', 'test_get_attach_displays', 'test_view', 'test_display_more', 'test_display_invalid', 'test_display_empty', 'test_exposed_relationship_admin_ui'); /** * Modules to enable. @@ -310,6 +310,31 @@ public function testInvalidDisplayPlugins() { $this->assertNoBlockAppears($block); } + /** + * Tests display validation when a required relationship is missing. + */ + public function testMissingRelationship() { + $view = Views::getView('test_exposed_relationship_admin_ui'); + + // Remove the relationship that is not used by other handlers. + $view->removeHandler('default', 'relationship', 'uid_1'); + $errors = $view->validate(); + // Check that no error message is shown. + $this->assertTrue(empty($errors['default']), 'No errors found when removing unused relationship.'); + + // Unset cached relationships (see DisplayPluginBase::getHandlers()) + unset($view->display_handler->handlers['relationship']); + + // Remove the relationship used by other handlers. + $view->removeHandler('default', 'relationship', 'uid'); + // Validate display + $errors = $view->validate(); + // Check that the error messages are shown. + $this->assertTrue(count($errors['default']) == 2, 'Error messages found for required relationship'); + $this->assertEqual($errors['default'][0], t('The %handler_type %handler uses a relationship that has been removed.', array('%handler_type' => 'field', '%handler' => 'User: Last login'))); + $this->assertEqual($errors['default'][1], t('The %handler_type %handler uses a relationship that has been removed.', array('%handler_type' => 'field', '%handler' => 'User: Created'))); + } + /** * Tests the outputIsEmpty method on the display. */ diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_relationship_admin_ui.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_relationship_admin_ui.yml new file mode 100644 index 0000000000000000000000000000000000000000..9a196a55f8686d5c6da265c939904f513828a5e9 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_relationship_admin_ui.yml @@ -0,0 +1,281 @@ +langcode: en +status: true +dependencies: + module: + - node + - user +id: test_exposed_relationship_admin_ui +label: test_exposed_relationship_admin_ui +module: views +description: '' +tag: '' +base_table: node +base_field: nid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: none + 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: full + 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: '‹ previous' + next: 'next ›' + first: '« first' + last: 'last »' + quantity: 9 + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + uses_fields: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + 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 + link_to_node: true + plugin_id: node + 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 + login: + id: login + table: users_field_data + field: login + relationship: uid + group_type: group + admin_label: '' + label: '' + 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: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + date_format: fallback + custom_date_format: '' + timezone: '' + entity_type: user + entity_field: login + plugin_id: date + created: + id: created + table: users_field_data + field: created + relationship: uid + group_type: group + admin_label: '' + label: '' + 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: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + date_format: fallback + custom_date_format: '' + timezone: '' + entity_type: user + entity_field: created + plugin_id: date + filters: + status: + value: true + table: node_field_data + field: status + plugin_id: boolean + entity_type: node + entity_field: status + id: status + expose: + operator: '' + group: 1 + 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: '' + granularity: second + header: { } + footer: { } + empty: { } + relationships: + uid: + id: uid + table: node_field_data + field: uid + relationship: none + group_type: group + admin_label: author + required: false + entity_type: node + entity_field: uid + plugin_id: standard + uid_1: + id: uid_1 + table: node_field_data + field: uid + relationship: none + group_type: group + admin_label: 'author 2' + required: false + entity_type: node + entity_field: uid + plugin_id: standard + arguments: { } + display_extenders: { } +