diff --git a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php index 472ed20..9c75f8f 100644 --- a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php +++ b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php @@ -152,7 +152,9 @@ public function getFieldTableName($field_name) { // https://www.drupal.org/node/2274017. /** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $storage */ $storage = \Drupal::entityManager()->getStorage($this->entityType->id()); + $storage_definition = $this->fieldStorageDefinitions[$field_name]; $table_names = array( + $this->getDedicatedDataTableName($storage_definition), $storage->getDataTable(), $storage->getBaseTable(), $storage->getRevisionTable(), @@ -160,7 +162,6 @@ public function getFieldTableName($field_name) { // Collect field columns. $field_columns = array(); - $storage_definition = $this->fieldStorageDefinitions[$field_name]; foreach (array_keys($storage_definition->getColumns()) as $property_name) { $field_columns[] = $this->getFieldColumnName($storage_definition, $property_name); } diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php index 2b4f9a4..3f2bc0b 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -287,13 +287,13 @@ public function getTableMapping(array $storage_definitions = NULL) { $definitions = $storage_definitions ?: $this->entityManager->getFieldStorageDefinitions($this->entityTypeId); $table_mapping = new DefaultTableMapping($this->entityType, $definitions); - $definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) { + $shared_table_definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) { return $table_mapping->allowsSharedTableStorage($definition); }); $key_fields = array_values(array_filter(array($this->idKey, $this->revisionKey, $this->bundleKey, $this->uuidKey, $this->langcodeKey))); - $all_fields = array_keys($definitions); - $revisionable_fields = array_keys(array_filter($definitions, function (FieldStorageDefinitionInterface $definition) { + $all_fields = array_keys($shared_table_definitions); + $revisionable_fields = array_keys(array_filter($shared_table_definitions, function (FieldStorageDefinitionInterface $definition) { return $definition->isRevisionable(); })); // Make sure the key fields come first in the list of fields. @@ -360,8 +360,8 @@ public function getTableMapping(array $storage_definitions = NULL) { } // Add dedicated tables. - $definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) { - return $table_mapping->requiresDedicatedTableStorage($definition); + $dedicated_table_definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) { + return $table_mapping->requiresDedicatedTableStorage($definition) && $definition->isBaseField(); }); $extra_columns = array( 'bundle', @@ -371,8 +371,12 @@ public function getTableMapping(array $storage_definitions = NULL) { 'langcode', 'delta', ); - foreach ($definitions as $field_name => $definition) { - foreach (array($table_mapping->getDedicatedDataTableName($definition), $table_mapping->getDedicatedRevisionTableName($definition)) as $table_name) { + foreach ($dedicated_table_definitions as $field_name => $definition) { + $tables = [$table_mapping->getDedicatedDataTableName($definition)]; + if ($revisionable && $definition->isRevisionable()) { + $tables[] = $table_mapping->getDedicatedRevisionTableName($definition); + } + foreach ($tables as $table_name) { $table_mapping->setFieldNames($table_name, array($field_name)); $table_mapping->setExtraColumns($table_name, $extra_columns); } @@ -1587,7 +1591,13 @@ public function finalizePurge(FieldStorageDefinitionInterface $storage_definitio * {@inheritdoc} */ public function countFieldData($storage_definition, $as_bool = FALSE) { - $table_mapping = $this->getTableMapping(); + // The existing table mapping cannot be relied upon because it may have been + // generated for after a schema update, so force the table mapping for the + // supplied storage definition. + // @todo This may be able to be removed once we are able to generate a fresh + // table mapping in the schema handler. See + // https://www.drupal.org/node/2274017. + $table_mapping = $this->getTableMapping([$storage_definition->getName() => $storage_definition]); if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) { $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index bc355f9..0421d00 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -230,11 +230,21 @@ public function getViewsData() { // Load all typed data definitions of all fields. This should cover each of // the entity base, revision, data tables. $field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id()); - if ($table_mapping = $this->storage->getTableMapping()) { + if ($table_mapping = $this->storage->getTableMapping($field_definitions)) { // Fetch all fields that can appear in both the base table and the data // table. $entity_keys = $this->entityType->getKeys(); $duplicate_fields = array_intersect_key($entity_keys, array_flip(['id', 'revision', 'bundle'])); + // Make note of some information so that table joins can be applied for + // base fields that have dedicated tables. + $main_tables = array_filter([$base_table, $data_table, $revision_table, $revision_data_table]); + $dedicated_data_tables = []; + foreach ($field_definitions as $field_name => $field_definition) { + $storage_definition = $field_definition->getFieldStorageDefinition(); + if ($revisionable && $storage_definition->isMultiple()) { + $dedicated_data_tables[] = $table_mapping->getFieldTableName($field_name); + } + } // Iterate over each table we have so far and collect field data for each. // Based on whether the field is in the field_definitions provided by the // entity manager. @@ -242,6 +252,19 @@ public function getViewsData() { // storage. // @todo https://www.drupal.org/node/2337511 foreach ($table_mapping->getTableNames() as $table) { + // Provide joins for base fields with dedicated storage. + if (!in_array($table, $main_tables)) { + $data[$table]['table']['group'] = in_array($table, $dedicated_data_tables) ? $this->entityType->getLabel() : $this->t('@entity_type revision', ['@entity_type' => $this->entityType->getLabel()]); + $data[$table]['table']['provider'] = $this->entityType->getProvider(); + $data[$table]['table']['join'][$views_base_table] = [ + 'left_field' => $base_field, + 'field' => 'entity_id', + 'extra' => array( + array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE), + ), + ]; + } + foreach ($table_mapping->getFieldNames($table) as $field_name) { // To avoid confusing duplication in the user interface, for fields // that are on both base and data tables, only add them on the data