diff --git a/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml b/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml index 5e6897c0dd..fbf1f012d1 100644 --- a/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml +++ b/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml @@ -133,7 +133,7 @@ display: url_plain: false rel: '0' target: '0' - group_column: '' + group_column: uri group_columns: { } group_rows: true delta_limit: 0 diff --git a/core/modules/media/config/optional/views.view.media.yml b/core/modules/media/config/optional/views.view.media.yml index cbcb293bb5..fb7c12e9b3 100644 --- a/core/modules/media/config/optional/views.view.media.yml +++ b/core/modules/media/config/optional/views.view.media.yml @@ -134,7 +134,7 @@ display: image_style: thumbnail image_loading: attribute: lazy - group_column: '' + group_column: target_id group_columns: { } group_rows: true delta_limit: 0 diff --git a/core/modules/views/src/Plugin/views/field/EntityField.php b/core/modules/views/src/Plugin/views/field/EntityField.php index d697d52031..f692e8bd60 100644 --- a/core/modules/views/src/Plugin/views/field/EntityField.php +++ b/core/modules/views/src/Plugin/views/field/EntityField.php @@ -242,7 +242,7 @@ public function query($use_groupby = FALSE) { unset($fields[$entity_type_key]); } - if ($use_groupby) { + if ($use_groupby && !empty($this->options['group_column'])) { // Add the fields that we're actually grouping on. $options = []; if ($this->options['group_column'] != 'entity_id') { @@ -277,7 +277,7 @@ public function query($use_groupby = FALSE) { */ public function add_field_table($use_groupby) { // Grouping is enabled. - if ($use_groupby) { + if ($use_groupby && !empty($this->options['group_column'])) { return TRUE; } // This a multiple value field, but "group multiple values" is not checked. @@ -368,17 +368,15 @@ protected function defineOptions() { $field_storage_definition = $this->getFieldStorageDefinition(); $field_type = $this->fieldTypePluginManager->getDefinition($field_storage_definition->getType()); - $column_names = array_keys($field_storage_definition->getColumns()); - $default_column = ''; - // Try to determine a sensible default. - if (count($column_names) == 1) { + + // Use the field's main property as default column. If the field item does + // not define a main property, use the first column as default column. + $default_column = $field_storage_definition->getMainPropertyName(); + if (empty($default_column)) { + $column_names = array_keys($field_storage_definition->getColumns()); $default_column = $column_names[0]; } - elseif (in_array('value', $column_names)) { - $default_column = 'value'; - } - // If the field has a "value" column, we probably need that one. $options['click_sort_column'] = [ 'default' => $default_column, ]; diff --git a/core/modules/views/src/ViewsConfigUpdater.php b/core/modules/views/src/ViewsConfigUpdater.php index 2ddb741c0a..026bd494bd 100644 --- a/core/modules/views/src/ViewsConfigUpdater.php +++ b/core/modules/views/src/ViewsConfigUpdater.php @@ -144,6 +144,9 @@ public function updateAll(ViewEntityInterface $view) { if ($this->processImageLazyLoadFieldHandler($handler, $handler_type, $view)) { $changed = TRUE; } + if ($this->processEmptyGroupColumn($handler, $handler_type, $key, $display_id, $view)) { + $changed = TRUE; + } return $changed; }); } @@ -561,4 +564,81 @@ protected function processSortFieldIdentifierUpdateHandler(array &$handler, stri return FALSE; } + /** + * Checks if there are any fields that have an empty group_column. + * + * @param \Drupal\views\ViewEntityInterface $view + * The View to update. + * + * @return bool + * Whether the view was updated. + */ + public function needsFixForEmptyGroupColumn(ViewEntityInterface $view) { + return $this->processDisplayHandlers($view, TRUE, function (&$handler, $handler_type, $key, $display_id) use ($view) { + return $this->processEmptyGroupColumn($handler, $handler_type, $key, $display_id, $view); + }); + } + + /** + * Fixes empty group columns. + * + * Some fields could be saved without a group column, this assures that every + * field has a default group column. + * + * @param array $handler + * A display handler. + * @param string $handler_type + * The handler type. + * @param string $key + * The handler key. + * @param string $display_id + * The handler display ID. + * @param \Drupal\views\ViewEntityInterface $view + * The view being updated. + */ + public function processEmptyGroupColumn(&$handler, string $handler_type, $key, $display_id, ViewEntityInterface $view): bool { + if ($handler_type !== 'field') { + return FALSE; + } + $changed = FALSE; + if (!empty($handler['plugin_id']) && $handler['plugin_id'] === 'field' && isset($handler['group_column']) && empty($handler['group_column'])) { + // Attempt to load the field storage definition of the field. + $executable = $view->getExecutable(); + $executable->setDisplay($display_id); + /** @var \Drupal\views\Plugin\views\field\FieldHandlerInterface $field_handler */ + $field_handler = $executable->getDisplay()->getHandler('field', $handler['id']); + if ($entity_type_id = $field_handler->getEntityType()) { + $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_id); + + $field_storage = NULL; + if (isset($handler['field']) && isset($field_storage_definitions[$handler['field']])) { + $field_storage = $field_storage_definitions[$handler['field']]; + } + elseif (isset($handler['entity_field']) && isset($field_storage_definitions[$handler['entity_field']])) { + $field_storage = $field_storage_definitions[$handler['entity_field']]; + } + if ($field_storage !== NULL) { + // Use the field's main property as default column. If the field + // item does not define a main property, use the first column as + // default column. + $default_column = $field_storage->getMainPropertyName(); + if (empty($default_column)) { + $column_names = array_keys($field_storage->getColumns()); + $default_column = $column_names[0]; + } + $handler['group_column'] = $default_column; + $changed = TRUE; + } + } + } + + $deprecations_triggered = &$this->triggeredDeprecations['2815881'][$view->id()]; + if ($this->deprecationsEnabled && $changed && !$deprecations_triggered) { + $deprecations_triggered = TRUE; + @trigger_error(sprintf('The field "%s" has its "group_column" set to an empty value for the "%s" view. This is deprecated in drupal:9.4.0 and is disallowed in drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/3255641.', $handler['field'], $view->id()), E_USER_DEPRECATED); + } + + return $changed; + } + } diff --git a/core/modules/views/tests/fixtures/update/empty-field-group-column.php b/core/modules/views/tests/fixtures/update/empty-field-group-column.php new file mode 100644 index 0000000000..e185d2c269 --- /dev/null +++ b/core/modules/views/tests/fixtures/update/empty-field-group-column.php @@ -0,0 +1,19 @@ +insert('config') + ->fields([ + 'collection' => '', + 'name' => 'views.view.group_column_post_update', + 'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/fixtures/update/views.view.group_column_post_update.yml'))), + ]) + ->execute(); diff --git a/core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml b/core/modules/views/tests/fixtures/update/views.view.group_column_post_update.yml similarity index 64% copy from core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml copy to core/modules/views/tests/fixtures/update/views.view.group_column_post_update.yml index 76684c71c5..3e1ee9a11b 100644 --- a/core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml +++ b/core/modules/views/tests/fixtures/update/views.view.group_column_post_update.yml @@ -1,19 +1,20 @@ -uuid: 001475a0-daec-4e8a-8ca7-97b0d24100a6 +uuid: 34a9177d-f979-4823-a40e-863199f39df1 langcode: en status: true dependencies: config: - - field.storage.user.user_picture + - field.storage.node.field_image module: - image + - node - user -id: test_user_multi_value -label: test_user_multi_value +id: group_column_post_update +label: 'group column post update' module: views description: '' tag: '' -base_table: users_field_data -base_field: uid +base_table: node_field_data +base_field: nid display: default: display_plugin: default @@ -24,7 +25,7 @@ display: access: type: perm options: - perm: 'access user profiles' + perm: 'access content' cache: type: tag options: { } @@ -39,7 +40,7 @@ display: exposed_form: type: basic options: - submit_button: Filter + submit_button: Apply reset_button: false reset_button_label: Reset exposed_sorts_label: 'Sort by' @@ -66,23 +67,65 @@ display: next: ›› style: type: default - options: - grouping: { } - row_class: '' - default_row_class: true - uses_fields: false row: type: fields options: + default_field_elements: true inline: { } separator: '' hide_empty: false - default_field_elements: true fields: - roles: - id: roles - table: user__roles - field: roles + 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: '' + 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 + field_image: + id: field_image + table: node__field_image + field: field_image relationship: none group_type: group admin_label: '' @@ -128,10 +171,11 @@ display: empty_zero: false hide_alter_empty: true click_sort_column: target_id - type: entity_reference_label + type: image settings: - link: true - group_column: target_id + image_style: '' + image_link: '' + group_column: '' group_columns: { } group_rows: true delta_limit: 0 @@ -141,13 +185,11 @@ display: multi_type: separator separator: ', ' field_api_classes: false - entity_type: user - entity_field: roles plugin_id: field - user_picture: - id: user_picture - table: user__user_picture - field: user_picture + field_image2: + id: field_image2 + table: node__field_image + field: field_image relationship: none group_type: group admin_label: '' @@ -197,8 +239,8 @@ display: settings: image_style: '' image_link: '' - group_column: '' - group_columns: { } + group_column: entity_id + group_columns: { } group_rows: true delta_limit: 0 delta_offset: 0 @@ -209,99 +251,65 @@ display: field_api_classes: false plugin_id: field filters: - roles: - id: roles - table: user__roles - field: roles + status: + value: '1' + 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: '' - operator: '=' - value: '' - group: 1 exposed: false expose: - operator_id: '' label: '' - description: '' - use_operator: false - operator: '' - 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: user - entity_field: roles - plugin_id: string - sorts: { } + granularity: second + title: 'image post update' header: { } footer: { } empty: { } relationships: { } - arguments: - roles: - id: roles - table: user__roles - field: roles - relationship: none - group_type: group - admin_label: '' - default_action: ignore - exception: - value: all - title_enable: false - title: All - title_enable: false - title: '' - default_argument_type: fixed - default_argument_options: - argument: '' - default_argument_skip_url: false - summary_options: - base_path: '' - count: true - items_per_page: 25 - override: false - summary: - sort_order: asc - number_of_records: 0 - format: default_summary - specify_validation: false - validate: - type: none - fail: 'not found' - validate_options: { } - glossary: false - limit: 0 - case: none - path_case: none - transform_dash: false - break_phrase: false - entity_type: user - entity_field: roles - plugin_id: string + 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: + - 'config:field.storage.node.field_image' + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: display_extenders: { } + path: image-post-update cache_metadata: max-age: -1 contexts: - 'languages:language_content' - 'languages:language_interface' - - url - url.query_args + - 'user.node_grants:view' - user.permissions tags: - - 'config:field.storage.user.user_picture' + - 'config:field.storage.node.field_image' diff --git a/core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml b/core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml index 76684c71c5..a43fbf8546 100644 --- a/core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml +++ b/core/modules/views/tests/fixtures/update/views.view.test_user_multi_value.yml @@ -197,7 +197,7 @@ display: settings: image_style: '' image_link: '' - group_column: '' + group_column: value group_columns: { } group_rows: true delta_limit: 0 diff --git a/core/modules/views/tests/src/Functional/Update/EmptyFieldGroupColumnUpdateTest.php b/core/modules/views/tests/src/Functional/Update/EmptyFieldGroupColumnUpdateTest.php new file mode 100644 index 0000000000..bbb2728ae7 --- /dev/null +++ b/core/modules/views/tests/src/Functional/Update/EmptyFieldGroupColumnUpdateTest.php @@ -0,0 +1,53 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-9.0.0.bare.standard.php.gz', + __DIR__ . '/../../../fixtures/update/empty-field-group-column.php', + ]; + } + + /** + * Tests that empty field group column values are updated properly. + */ + public function testViewsPostUpdateEmptyFieldGroupColumn() { + // Load and initialize our test view to validate our starting values. + $view = View::load('group_column_post_update'); + $data = $view->toArray(); + // Check that the field is using the wrong default value. + $this->assertSame('', $data['display']['default']['display_options']['fields']['field_image']['group_column']); + $this->assertSame('', $data['display']['default']['display_options']['fields']['title']['group_column']); + // Ensure existing values are not changed. + $this->assertSame('entity_id', $data['display']['default']['display_options']['fields']['field_image2']['group_column']); + + $this->runUpdates(); + + // Load and initialize our test view. + $view = View::load('group_column_post_update'); + $data = $view->toArray(); + // Check that the field is using the expected default value. + $this->assertSame('target_id', $data['display']['default']['display_options']['fields']['field_image']['group_column']); + $this->assertSame('value', $data['display']['default']['display_options']['fields']['title']['group_column']); + // Ensure existing values are not changed. + $this->assertSame('entity_id', $data['display']['default']['display_options']['fields']['field_image2']['group_column']); + } + +} diff --git a/core/modules/views/tests/src/Kernel/QueryGroupByTest.php b/core/modules/views/tests/src/Kernel/QueryGroupByTest.php index 171688321e..80d48e5195 100644 --- a/core/modules/views/tests/src/Kernel/QueryGroupByTest.php +++ b/core/modules/views/tests/src/Kernel/QueryGroupByTest.php @@ -3,10 +3,14 @@ namespace Drupal\Tests\views\Kernel; use Drupal\Component\Render\FormattableMarkup; +use Drupal\entity_test\Entity\EntityTest; use Drupal\entity_test\Entity\EntityTestMul; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; +use Drupal\file\Entity\File; +use Drupal\image\Entity\ImageStyle; use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\views\Entity\View; use Drupal\views\Views; /** @@ -28,6 +32,7 @@ class QueryGroupByTest extends ViewsKernelTestBase { 'test_group_by_count', 'test_group_by_count_multicardinality', 'test_group_by_field_not_within_bundle', + 'entity_test_fields', ]; /** @@ -41,6 +46,8 @@ class QueryGroupByTest extends ViewsKernelTestBase { 'field', 'user', 'language', + 'file', + 'image', ]; /** @@ -357,4 +364,84 @@ public function testGroupByWithFieldsNotExistingOnBundle() { $this->assertEquals('1', $view->getStyle()->getField(1, 'field_test')); } + /** + * Tests aggregation on fields with multiple columns. + */ + public function testGroupByFieldWithMultipleColumns() { + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('file'); + $this->installSchema('file', 'file_usage'); + /** @var \Drupal\image\ImageStyleInterface $style */ + $style = ImageStyle::create(['name' => 'foo']); + $style->save(); + + // Create a new image field 'bar' to be used in 'entity_test_fields' view. + FieldStorageConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'image_field', + 'type' => 'image', + ])->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + 'field_name' => 'image_field', + 'settings' => [ + 'file_extensions' => 'jpg', + ], + ])->save(); + + /** @var \Drupal\views\ViewEntityInterface $view */ + $view = View::load('entity_test_fields'); + $display =& $view->getDisplay('default'); + + // Set the image field as the only field so it should be used for grouping + // when aggregation is enabled. + $display['display_options']['fields'] = [ + 'image_field' => [ + 'id' => 'image_field', + 'field' => 'image_field', + 'plugin_id' => 'field', + 'table' => 'entity_test__image_field', + 'entity_type' => 'entity_test', + 'entity_field' => 'image_field', + 'type' => 'image', + 'settings' => ['image_style' => 'foo', 'image_link' => ''], + ], + ]; + $display['display_options']['arguments'] = []; + $display['display_options']['sorts'] = []; + $display['display_options']['group_by'] = TRUE; + $view->save(); + + $file = File::create([ + 'filename' => 'druplicon.jpg', + 'uri' => "public://druplicon.jpg", + 'filemime' => 'image/jpeg', + 'status' => FILE_STATUS_PERMANENT, + ]); + $file_two = File::create([ + 'filename' => 'druplicon-two.jpg', + 'uri' => "public://druplicon-two.jpg", + 'filemime' => 'image/jpeg', + 'status' => FILE_STATUS_PERMANENT, + ]); + + $entity_one = EntityTest::create(); + $entity_one->set('image_field', $file); + $entity_one->save(); + + $entity_two = EntityTest::create(); + $entity_two->set('image_field', $file); + $entity_two->save(); + + $entity_three = EntityTest::create(); + $entity_three->set('image_field', $file_two); + $entity_three->save(); + + $view_executable = $view->getExecutable(); + $this->executeView($view_executable); + // By default the rows should now be grouped by target_id. + $this->assertCount(2, $view_executable->result); + } + } diff --git a/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php b/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php index f3549c4621..7407e1f6a6 100644 --- a/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php @@ -511,6 +511,71 @@ public function testQueryWithGroupByForBaseField() { $handler->query(TRUE); } + /** + * @covers ::query + */ + public function testQueryWithGroupByForBaseFieldFailure() { + $definition = [ + 'entity_type' => 'test_entity', + 'field_name' => 'title', + ]; + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler->view = $this->executable; + $handler->view->field = [$handler]; + + $this->setupLanguageRenderer($handler, $definition); + + $field_storage = $this->getBaseFieldStorage(); + $this->entityFieldManager->expects($this->any()) + ->method('getFieldStorageDefinitions') + ->with('test_entity') + ->willReturn([ + 'title' => $field_storage, + ]); + + $table_mapping = $this->createMock('Drupal\Core\Entity\Sql\TableMappingInterface'); + $table_mapping + ->expects($this->any()) + ->method('getFieldColumnName') + ->with($field_storage, 'value') + ->willReturn('title'); + $entity_storage = $this->createMock('Drupal\Core\Entity\Sql\SqlEntityStorageInterface'); + $entity_storage->expects($this->any()) + ->method('getTableMapping') + ->willReturn($table_mapping); + $this->entityTypeManager->expects($this->any()) + ->method('getStorage') + ->with('test_entity') + ->willReturn($entity_storage); + + $options = [ + 'group_column' => NULL, + 'group_columns' => [], + 'table' => 'test_entity_table', + ]; + $handler->init($this->executable, $this->display, $options); + + $query = $this->getMockBuilder('Drupal\views\Plugin\views\query\Sql') + ->disableOriginalConstructor() + ->getMock(); + $query->expects($this->any()) + ->method('ensureTable') + ->with('test_entity_table', NULL) + ->willReturn('test_entity_table'); + // Ensure that we add the title field to the query, if we group by some + // other field in the view. + $query->expects($this->any()) + ->method('addField') + ->with('test_entity_table', 'title'); + + $this->executable->query = $query; + + $handler->query(TRUE); + + $this->assertObjectNotHasAttribute('group_fields', $handler); + $this->assertNull($handler->tableAlias); + } + /** * @covers ::query */ @@ -573,6 +638,71 @@ public function testQueryWithGroupByForConfigField() { $handler->query(TRUE); } + /** + * @covers ::query + */ + public function testQueryWithGroupByForConfigFieldFailure() { + $definition = [ + 'entity_type' => 'test_entity', + 'field_name' => 'body', + ]; + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler->view = $this->executable; + $handler->view->field = [$handler]; + + $this->setupLanguageRenderer($handler, $definition); + + $field_storage = $this->getConfigFieldStorage(); + $this->entityFieldManager->expects($this->any()) + ->method('getFieldStorageDefinitions') + ->with('test_entity') + ->willReturn([ + 'body' => $field_storage, + ]); + + $table_mapping = $this->createMock('Drupal\Core\Entity\Sql\TableMappingInterface'); + $table_mapping + ->expects($this->any()) + ->method('getFieldColumnName') + ->with($field_storage, 'value') + ->willReturn('body_value'); + $entity_storage = $this->createMock('Drupal\Core\Entity\Sql\SqlEntityStorageInterface'); + $entity_storage->expects($this->any()) + ->method('getTableMapping') + ->willReturn($table_mapping); + $this->entityTypeManager->expects($this->any()) + ->method('getStorage') + ->with('test_entity') + ->willReturn($entity_storage); + + $options = [ + 'group_column' => NULL, + 'group_columns' => [], + 'table' => 'test_entity__body', + ]; + $handler->init($this->executable, $this->display, $options); + + $query = $this->getMockBuilder('Drupal\views\Plugin\views\query\Sql') + ->disableOriginalConstructor() + ->getMock(); + $query->expects($this->any()) + ->method('ensureTable') + ->with('test_entity__body', NULL) + ->willReturn('test_entity__body'); + // Ensure that we add the title field to the query, if we group by some + // other field in the view. + $query->expects($this->any()) + ->method('addField') + ->with('test_entity__body', 'body_value'); + + $this->executable->query = $query; + + $handler->query(TRUE); + + $this->assertObjectNotHasAttribute('group_fields', $handler); + $this->assertNull($handler->tableAlias); + } + /** * @covers ::prepareItemsByDelta * @@ -741,6 +871,60 @@ protected function setupLanguageRenderer(EntityField $handler, $definition) { ->willReturn($entity_type); } + /** + * @covers ::add_field_table + */ + public function testAddAdditionalFieldTable() { + $definition = [ + 'entity_type' => 'test_entity', + 'field_name' => 'body', + ]; + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler->view = $this->executable; + $handler->view->field = [$handler]; + + $this->setupLanguageRenderer($handler, $definition); + + $field_storage = $this->getConfigFieldStorage(); + $this->entityFieldManager->expects($this->any()) + ->method('getFieldStorageDefinitions') + ->with('test_entity') + ->willReturn([ + 'body' => $field_storage, + ]); + + $table_mapping = $this->createMock('Drupal\Core\Entity\Sql\TableMappingInterface'); + $table_mapping + ->expects($this->any()) + ->method('getFieldColumnName') + ->with($field_storage, 'value') + ->willReturn('body_value'); + $entity_storage = $this->createMock('Drupal\Core\Entity\Sql\SqlEntityStorageInterface'); + $entity_storage->expects($this->any()) + ->method('getTableMapping') + ->willReturn($table_mapping); + $this->entityTypeManager->expects($this->any()) + ->method('getStorage') + ->with('test_entity') + ->willReturn($entity_storage); + + $options = [ + 'group_column' => NULL, + 'group_columns' => [], + 'table' => 'test_entity__body', + ]; + $handler->init($this->executable, $this->display, $options); + $handler->query = $this->getMockBuilder('Drupal\views\Plugin\views\query\Sql') + ->disableOriginalConstructor() + ->getMock(); + + $handler->additional_fields = ['alt', 'title']; + $handler->query(TRUE); + + $this->assertEmpty($handler->tableAlias); + $this->assertEmpty($handler->aliases); + } + } class FieldTestEntityField extends EntityField { diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php index 66291097b8..2e27e64358 100644 --- a/core/modules/views/views.post_update.php +++ b/core/modules/views/views.post_update.php @@ -77,6 +77,18 @@ function views_post_update_title_translations() { \Drupal::service('router.builder')->setRebuildNeeded(); } +/** + * Fix views containing entity fields with an empty group column value set. + */ +function views_post_update_empty_entity_field_group_column(?array &$sandbox = NULL) { + /** @var \Drupal\views\ViewsConfigUpdater $view_config_updater */ + $view_config_updater = \Drupal::classResolver(ViewsConfigUpdater::class); + $view_config_updater->setDeprecationsEnabled(FALSE); + \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($view_config_updater) { + return $view_config_updater->needsFixForEmptyGroupColumn($view); + }); +} + /** * Add the identifier option to all sort handler configurations. */ diff --git a/core/profiles/demo_umami/config/optional/views.view.media.yml b/core/profiles/demo_umami/config/optional/views.view.media.yml index dc3b7e813f..ea5651511c 100644 --- a/core/profiles/demo_umami/config/optional/views.view.media.yml +++ b/core/profiles/demo_umami/config/optional/views.view.media.yml @@ -134,7 +134,7 @@ display: image_link: '' image_loading: attribute: lazy - group_column: '' + group_column: target_id group_columns: { } group_rows: true delta_limit: 0