diff --git a/core/modules/user/src/UserViewsData.php b/core/modules/user/src/UserViewsData.php index e2229112eb..6a92ca8c7c 100644 --- a/core/modules/user/src/UserViewsData.php +++ b/core/modules/user/src/UserViewsData.php @@ -220,34 +220,20 @@ public function getViewsData() { ), ); - $data['user__roles']['table']['group'] = $this->t('User'); + // Alter the user roles target_id column. + $data['user__roles']['roles_target_id']['field']['id'] = 'user_roles'; + $data['user__roles']['roles_target_id']['field']['no group by'] = TRUE; - $data['user__roles']['table']['join'] = array( - 'users_field_data' => array( - 'left_field' => 'uid', - 'field' => 'entity_id', - ), - ); + $data['user__roles']['roles_target_id']['filter']['id'] = 'user_roles'; + $data['user__roles']['roles_target_id']['filter']['allow empty'] = TRUE; - $data['user__roles']['roles_target_id'] = array( - 'title' => $this->t('Roles'), - 'help' => $this->t('Roles that a user belongs to.'), - 'field' => array( - 'id' => 'user_roles', - 'no group by' => TRUE, - ), - 'filter' => array( - 'id' => 'user_roles', - 'allow empty' => TRUE, - ), - 'argument' => array( - 'id' => 'user__roles_rid', - 'name table' => 'role', - 'name field' => 'name', - 'empty field name' => $this->t('No role'), - 'zero is null' => TRUE, - 'numeric' => TRUE, - ), + $data['user__roles']['roles_target_id']['argument'] = array( + 'id' => 'user__roles_rid', + 'name table' => 'role', + 'name field' => 'name', + 'empty field name' => $this->t('No role'), + 'zero is null' => TRUE, + 'numeric' => TRUE, ); $data['user__roles']['permission'] = array( diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index 61def5acd4..4459af4ba0 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -371,13 +371,10 @@ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterf // @todo Introduce concept of the "main" column for a field, rather than // assuming the first one is the main column. See also what the // mapSingleFieldViewsData() method does with $first. - $multiple = (count($field_column_mapping) > 1); $first = TRUE; foreach ($field_column_mapping as $field_column_name => $schema_field_name) { - $views_field_name = ($multiple) ? $field_name . '__' . $field_column_name : $field_name; - $table_data[$views_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition); - - $table_data[$views_field_name]['entity field'] = $field_name; + $table_data[$schema_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition); + $table_data[$schema_field_name]['entity field'] = $field_name; $first = FALSE; } } diff --git a/core/modules/views/src/Tests/Update/EntityViewsMultiValueBaseFieldDataUpdateTest.php b/core/modules/views/src/Tests/Update/EntityViewsMultiValueBaseFieldDataUpdateTest.php new file mode 100644 index 0000000000..2631bb00fa --- /dev/null +++ b/core/modules/views/src/Tests/Update/EntityViewsMultiValueBaseFieldDataUpdateTest.php @@ -0,0 +1,50 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz', + ]; + } + + /** + * Tests multi-value base field views data is updated correctly. + */ + public function testUpdateMultiValueBaseFields() { + \Drupal::service('module_installer')->install(['entity_test', 'views_test_config']); + + ViewTestData::createTestViews(get_class($this), ['views_test_config']); + + $this->runUpdates(); + + $view = Views::getView('test_entity_multivalue_basefield_update'); + + // The field for this handler should get updated to use the correct field + // storage column name. + $display = $view->storage->get('display'); + $this->assertEqual('basefield_name', $view->storage->get($display['default']['display_options']['fields']['name']['field'])); + } + +} diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml index 478071dfa7..d2ecb577bf 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml @@ -30,7 +30,7 @@ display: name: id: name table: entity_test_multivalue_basefield__name - field: name + field: name_value plugin_id: field entity_type: entity_test_multivalue_basefield entity_field: name diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield_update.yml similarity index 95% copy from core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml copy to core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield_update.yml index 478071dfa7..803d32a15f 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_multivalue_basefield_update.yml @@ -3,7 +3,7 @@ status: true dependencies: module: - entity_test -id: test_entity_multivalue_basefield +id: test_entity_multivalue_basefield_update label: '' module: views description: '' diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php index acb84e5f1e..5a70eca30b 100644 --- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php +++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php @@ -470,7 +470,7 @@ public function testBaseTableFields() { ['description', ['value' => 'description__value', 'format' => 'description__format']], ['homepage', ['value' => 'homepage']], ['user_id', ['target_id' => 'user_id']], - ['string', ['value' => 'value']], + ['string', ['value' => 'string_value']], ]); $table_mapping->expects($this->any()) ->method('getFieldNames') @@ -527,8 +527,12 @@ public function testBaseTableFields() { $this->assertEquals('users_field_data', $relationship['base']); $this->assertEquals('uid', $relationship['base field']); - $this->assertStringField($data['entity_test__string']['string']); - $this->assertField($data['entity_test__string']['string'], 'string'); + // The string field name should be used as the 'entity field' but the actual + // field should reflect what the column mapping is using for multi-value + // base fields NOT just the field name. The actual column name returned from + // mappings in the test mocks is 'value'. + $this->assertStringField($data['entity_test__string']['string_value']); + $this->assertField($data['entity_test__string']['string_value'], 'string'); $this->assertEquals([ 'left_field' => 'id', 'field' => 'entity_id', @@ -592,7 +596,7 @@ public function testDataTableFields() { ['description', ['value' => 'description__value', 'format' => 'description__format']], ['homepage', ['value' => 'homepage']], ['user_id', ['target_id' => 'user_id']], - ['string', ['value' => 'value']], + ['string', ['value' => 'string_value']], ]); $table_mapping->expects($this->any()) ->method('getFieldNames') @@ -682,8 +686,8 @@ public function testDataTableFields() { $this->assertEquals('users_field_data', $relationship['base']); $this->assertEquals('uid', $relationship['base field']); - $this->assertStringField($data['entity_test_mul__string']['string']); - $this->assertField($data['entity_test_mul__string']['string'], 'string'); + $this->assertStringField($data['entity_test_mul__string']['string_value']); + $this->assertField($data['entity_test_mul__string']['string_value'], 'string'); $this->assertEquals([ 'left_field' => 'id', 'field' => 'entity_id', @@ -741,8 +745,8 @@ public function testRevisionTableFields() { ['description', ['value' => 'description__value', 'format' => 'description__format']], ['homepage', ['value' => 'homepage']], ['user_id', ['target_id' => 'user_id']], - ['revision_id', ['value' => 'id']], - ['string', ['value' => 'value']], + ['revision_id', ['value' => 'revision_id']], + ['string', ['value' => 'string_value']], ]); $table_mapping->expects($this->any()) ->method('getFieldNames') @@ -867,8 +871,8 @@ public function testRevisionTableFields() { $this->assertEquals('users_field_data', $relationship['base']); $this->assertEquals('uid', $relationship['base field']); - $this->assertStringField($data['entity_test_mulrev__string']['string']); - $this->assertField($data['entity_test_mulrev__string']['string'], 'string'); + $this->assertStringField($data['entity_test_mulrev__string']['string_value']); + $this->assertField($data['entity_test_mulrev__string']['string_value'], 'string'); $this->assertEquals([ 'left_field' => 'id', 'field' => 'entity_id', @@ -879,8 +883,8 @@ public function testRevisionTableFields() { ]], ], $data['entity_test_mulrev__string']['table']['join']['entity_test_mulrev_property_data']); - $this->assertStringField($data['entity_test_mulrev_revision__string']['string']); - $this->assertField($data['entity_test_mulrev_revision__string']['string'], 'string'); + $this->assertStringField($data['entity_test_mulrev_revision__string']['string_value']); + $this->assertField($data['entity_test_mulrev_revision__string']['string_value'], 'string'); $this->assertEquals([ 'left_field' => 'revision_id', 'field' => 'entity_id', diff --git a/core/modules/views/views.install b/core/modules/views/views.install index 8801a93bc1..82cdee53d5 100644 --- a/core/modules/views/views.install +++ b/core/modules/views/views.install @@ -415,3 +415,92 @@ function views_update_8201() { /** * @} End of "addtogroup updates-8.2.0". */ + +/** + * @addtogroup updates-8.3.0 + * @{ + */ + +/** + * Update field names for multi-value base fields. + */ +function views_update_8300() { + // Find all multi-value base fields for content entities. + $entity_type_manager = \Drupal::entityTypeManager(); + $entity_field_manager = \Drupal::service('entity_field.manager'); + $table_update_info = []; + + foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) { + if ($entity_type->hasHandlerClass('views_data')) { + $base_field_definitions = $entity_field_manager->getBaseFieldDefinitions($entity_type_id); + + $entity_storage = $entity_type_manager->getStorage($entity_type_id); + $table_mapping = $entity_storage->getTableMapping($base_field_definitions); + + foreach ($base_field_definitions as $field_name => $base_field_definition) { + $base_field_storage_definition = $base_field_definition->getFieldStorageDefinition(); + + // Skip single value and custom storage base fields. + if (!$base_field_storage_definition->isMultiple() || $base_field_storage_definition->hasCustomStorage()) { + continue; + } + + // Get the actual table, as well as the column for the main property + // name so we can perform an update later on the views. + $table_name = $table_mapping->getFieldTableName($field_name); + $main_property_name = $base_field_storage_definition->getMainPropertyName(); + + $table_update_info[$table_name][$field_name] = $table_mapping->getFieldColumnName($base_field_storage_definition, $main_property_name); + } + } + } + + if (empty($table_update_info)) { + return; + } + + $config_factory = \Drupal::configFactory(); + $handler_types = ['fields', 'arguments', 'sorts', 'relationships', 'filters']; + + foreach ($config_factory->listAll('views.view.') as $id) { + $view = $config_factory->getEditable($id); + $changed = FALSE; + + foreach ($view->get('display') as $display_id => &$display) { + foreach ($handler_types as $handler_type) { + $handler_data = $view->get("display.$display_id.display_options.$handler_type"); + + if (empty($handler_data)) { + continue; + } + + foreach ($handler_data as $key => $data) { + // If this handler has a table we're interested in, update the field + // name. + $table = $data['table']; + if (isset($table_update_info[$table])) { + $path = "display.$display_id.display_options.$handler_type.$key.field"; + $original_field_name = $view->get($path); + + // Only if the wrong field name is set do we change the field. It + // could already be using the correct field. Like + // user__roles/roles_target_id. + if (isset($table_update_info[$table][$original_field_name])) { + $view->set($path, $table_update_info[$table][$original_field_name]); + $changed = TRUE; + } + } + } + } + } + + if ($changed) { + $view->save(); + } + } + +} + +/** + * @} End of "addtogroup updates-8.3.0". + */