diff --git a/core/modules/block_content/src/BlockContentViewsData.php b/core/modules/block_content/src/BlockContentViewsData.php index aa23a534f84944070d0abf294d810b6d346c9de1..06c9de77f2286dcb4329bf4633f761903a029fe9 100644 --- a/core/modules/block_content/src/BlockContentViewsData.php +++ b/core/modules/block_content/src/BlockContentViewsData.php @@ -36,27 +36,6 @@ public function getViewsData() { $data['block_content_field_revision']['table']['base']['help'] = $this->t('Block Content revision is a history of changes to block content.'); $data['block_content_field_revision']['table']['base']['defaults']['title'] = 'info'; - // @todo EntityViewsData should add these relationships by default. - // https://www.drupal.org/node/2410275 - $data['block_content_field_revision']['id']['relationship']['id'] = 'standard'; - $data['block_content_field_revision']['id']['relationship']['base'] = 'block_content_field_data'; - $data['block_content_field_revision']['id']['relationship']['base field'] = 'id'; - $data['block_content_field_revision']['id']['relationship']['title'] = $this->t('Block Content'); - $data['block_content_field_revision']['id']['relationship']['label'] = $this->t('Get the actual block content from a block content revision.'); - - $data['block_content_field_revision']['revision_id']['relationship']['id'] = 'standard'; - $data['block_content_field_revision']['revision_id']['relationship']['base'] = 'block_content_field_data'; - $data['block_content_field_revision']['revision_id']['relationship']['base field'] = 'revision_id'; - $data['block_content_field_revision']['revision_id']['relationship']['title'] = $this->t('Block Content'); - $data['block_content_field_revision']['revision_id']['relationship']['label'] = $this->t('Get the actual block content from a block content revision.'); - - $data['block_content_revision']['revision_user']['help'] = $this->t('The user who created the revision.'); - $data['block_content_revision']['revision_user']['relationship']['label'] = $this->t('revision user'); - $data['block_content_revision']['revision_user']['filter']['id'] = 'user_name'; - - $data['block_content_revision']['table']['join']['block_content_field_data']['left_field'] = 'revision_id'; - $data['block_content_revision']['table']['join']['block_content_field_data']['field'] = 'revision_id'; - return $data; } diff --git a/core/modules/media/src/MediaViewsData.php b/core/modules/media/src/MediaViewsData.php index 2dc16496866b28b736917814fbe85afe7f1c50bf..393548be84c6c94ce6118ee6d62a842e0db64b60 100644 --- a/core/modules/media/src/MediaViewsData.php +++ b/core/modules/media/src/MediaViewsData.php @@ -18,13 +18,6 @@ public function getViewsData() { $data['media_field_data']['table']['wizard_id'] = 'media'; $data['media_field_revision']['table']['wizard_id'] = 'media_revision'; - $data['media_revision']['revision_user']['help'] = $this->t('The user who created the revision.'); - $data['media_revision']['revision_user']['relationship']['label'] = $this->t('revision user'); - $data['media_revision']['revision_user']['filter']['id'] = 'user_name'; - - $data['media_revision']['table']['join']['media_field_data']['left_field'] = 'vid'; - $data['media_revision']['table']['join']['media_field_data']['field'] = 'vid'; - $data['media_field_data']['status_extra'] = [ 'title' => $this->t('Published status or admin user'), 'help' => $this->t('Filters out unpublished media if the current user cannot view it.'), diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php index 32aa04c725dfc1fcbb7c14505ee6f0f7c03ffcb5..5c1d34cc74d330ccfed4e47125300434df3edd04 100644 --- a/core/modules/node/src/NodeViewsData.php +++ b/core/modules/node/src/NodeViewsData.php @@ -178,12 +178,6 @@ public function getViewsData() { ], ]; - $data['node_field_data']['uid']['help'] = $this->t('The user authoring the content. If you need more fields than the uid add the content: author relationship'); - $data['node_field_data']['uid']['filter']['id'] = 'user_name'; - $data['node_field_data']['uid']['relationship']['title'] = $this->t('Content author'); - $data['node_field_data']['uid']['relationship']['help'] = $this->t('Relate content to the user who created it.'); - $data['node_field_data']['uid']['relationship']['label'] = $this->t('author'); - $data['node']['node_listing_empty'] = [ 'title' => $this->t('Empty Node Frontpage behavior'), 'help' => $this->t('Provides a link to the node add overview page.'), @@ -211,45 +205,15 @@ public function getViewsData() { // @todo the NID field needs different behavior on revision/non-revision // tables. It would be neat if this could be encoded in the base field // definition. - $data['node_field_revision']['nid']['relationship']['id'] = 'standard'; - $data['node_field_revision']['nid']['relationship']['base'] = 'node_field_data'; - $data['node_field_revision']['nid']['relationship']['base field'] = 'nid'; - $data['node_field_revision']['nid']['relationship']['title'] = $this->t('Content'); - $data['node_field_revision']['nid']['relationship']['label'] = $this->t('Get the actual content from a content revision.'); - $data['node_field_revision']['nid']['relationship']['extra'][] = [ - 'field' => 'langcode', - 'left_field' => 'langcode', - ]; - $data['node_field_revision']['vid'] = [ 'argument' => [ 'id' => 'node_vid', 'numeric' => TRUE, ], - 'relationship' => [ - 'id' => 'standard', - 'base' => 'node_field_data', - 'base field' => 'vid', - 'title' => $this->t('Content'), - 'label' => $this->t('Get the actual content from a content revision.'), - 'extra' => [ - [ - 'field' => 'langcode', - 'left_field' => 'langcode', - ], - ], - ], ] + $data['node_field_revision']['vid']; $data['node_field_revision']['langcode']['help'] = $this->t('The language the original content is in.'); - $data['node_revision']['revision_uid']['help'] = $this->t('The user who created the revision.'); - $data['node_revision']['revision_uid']['relationship']['label'] = $this->t('revision user'); - $data['node_revision']['revision_uid']['filter']['id'] = 'user_name'; - - $data['node_revision']['table']['join']['node_field_data']['left_field'] = 'vid'; - $data['node_revision']['table']['join']['node_field_data']['field'] = 'vid'; - $data['node_field_revision']['table']['wizard_id'] = 'node_field_revision'; $data['node_field_revision']['status']['filter']['label'] = $this->t('Published'); diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index 87bfa116b3c5e681a544cd6de85804e23f547e36..2ae740d41bc87590ab0cc664f321b4f3ff17d7e3 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -2,6 +2,7 @@ namespace Drupal\views; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\ContentEntityType; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityHandlerInterface; @@ -132,7 +133,8 @@ public function getViewsData() { $base_table = $this->entityType->getBaseTable() ?: $this->entityType->id(); $views_revision_base_table = NULL; $revisionable = $this->entityType->isRevisionable(); - $base_field = $this->entityType->getKey('id'); + $entity_id_key = $this->entityType->getKey('id'); + $entity_keys = $this->entityType->getKeys(); $revision_table = ''; if ($revisionable) { @@ -153,7 +155,8 @@ public function getViewsData() { if ($revisionable && $translatable) { $revision_data_table = $this->entityType->getRevisionDataTable() ?: $this->entityType->id() . '_field_revision'; } - $revision_field = $this->entityType->getKey('revision'); + $entity_revision_key = $this->entityType->getKey('revision'); + $revision_field = $entity_revision_key; // Setup base information of the views data. $data[$base_table]['table']['group'] = $this->entityType->getLabel(); @@ -164,7 +167,7 @@ public function getViewsData() { $views_base_table = $data_table; } $data[$views_base_table]['table']['base'] = [ - 'field' => $base_field, + 'field' => $entity_id_key, 'title' => $this->entityType->getLabel(), 'cache_contexts' => $this->entityType->getListCacheContexts(), 'access query tag' => $this->entityType->id() . '_access', @@ -219,8 +222,8 @@ public function getViewsData() { // Setup relations to the revisions/property data. if ($data_table) { $data[$base_table]['table']['join'][$data_table] = [ - 'left_field' => $base_field, - 'field' => $base_field, + 'left_field' => $entity_id_key, + 'field' => $entity_id_key, 'type' => 'INNER', ]; $data[$data_table]['table']['group'] = $this->entityType->getLabel(); @@ -271,6 +274,33 @@ public function getViewsData() { 'filter' => ['id' => 'latest_translation_affected_revision'], ]; } + // Add a relationship from the revision table back to the main table. + $entity_type_label = $this->entityType->getLabel(); + $data[$views_revision_base_table][$entity_id_key]['relationship'] = [ + 'id' => 'standard', + 'base' => $views_base_table, + 'base field' => $entity_id_key, + 'title' => $entity_type_label, + 'help' => $this->t('Get the actual @label from a @label revision', ['@label' => $entity_type_label]), + ]; + $data[$views_revision_base_table][$entity_revision_key]['relationship'] = [ + 'id' => 'standard', + 'base' => $views_base_table, + 'base field' => $entity_revision_key, + 'title' => $this->t('@label revision', ['@label' => $entity_type_label]), + 'help' => $this->t('Get the actual @label from a @label revision', ['@label' => $entity_type_label]), + ]; + if ($translatable) { + $extra = [ + 'field' => $entity_keys['langcode'], + 'left_field' => $entity_keys['langcode'], + ]; + $data[$views_revision_base_table][$entity_id_key]['relationship']['extra'][] = $extra; + $data[$views_revision_base_table][$entity_revision_key]['relationship']['extra'][] = $extra; + $data[$revision_table]['table']['join'][$views_base_table]['left_field'] = $entity_revision_key; + $data[$revision_table]['table']['join'][$views_base_table]['field'] = $entity_revision_key; + } + } $this->addEntityLinks($data[$base_table]); @@ -285,7 +315,6 @@ public function getViewsData() { 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'])); // 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 @@ -312,7 +341,7 @@ public function getViewsData() { $data[$table]['table']['group'] = $this->entityType->getLabel(); $data[$table]['table']['provider'] = $this->entityType->getProvider(); $data[$table]['table']['join'][$views_base_table] = [ - 'left_field' => $base_field, + 'left_field' => $entity_id_key, 'field' => 'entity_id', 'extra' => [ ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE], @@ -334,6 +363,12 @@ public function getViewsData() { } } } + if (($uid_key = $entity_keys['uid'] ?? '')) { + $data[$data_table][$uid_key]['filter']['id'] = 'user_name'; + } + if ($revision_table && ($revision_uid_key = $this->entityType->getRevisionMetadataKeys()['revision_user'] ?? '')) { + $data[$revision_table][$revision_uid_key]['filter']['id'] = 'user_name'; + } } // Add the entity type key to each table generated. @@ -411,7 +446,10 @@ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterf // mapSingleFieldViewsData() method does with $first. $first = TRUE; foreach ($field_column_mapping as $field_column_name => $schema_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); + // The fields might be defined before the actual table. + $table_data = $table_data ?: []; + $table_data += [$schema_field_name => []]; + $table_data[$schema_field_name] = NestedArray::mergeDeep($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/tests/src/Kernel/Entity/EntityViewsDataTest.php b/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php index 372a4c4add80e1d4e608999eb4afd9e8fbfeb53a..c96792e93b085671d7e7421f48e994e2b18304a8 100644 --- a/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php +++ b/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php @@ -256,6 +256,11 @@ public function testRevisionTableWithoutDataTable() { $this->assertCount(1, $revision_data['table']['join']); $this->assertEquals(['entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']); $this->assertFalse(isset($data['data_table'])); + + $this->assertEquals('entity_test', $revision_data['id']['relationship']['base']); + $this->assertEquals('id', $revision_data['id']['relationship']['base field']); + $this->assertEquals('entity_test', $revision_data['revision_id']['relationship']['base']); + $this->assertEquals('revision_id', $revision_data['revision_id']['relationship']['base field']); } /** @@ -294,16 +299,25 @@ public function testRevisionTableWithRevisionDataTableAndDataTable() { ], $revision_field_data['table']['join']); $revision_base_data = $data['entity_test_mulrev_revision']; - $this->assertCount(1, $revision_base_data['table']['join']); + $this->assertCount(2, $revision_base_data['table']['join']); $this->assertEquals([ 'entity_test_mulrev_property_revision' => [ 'left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER', ], + 'entity_test_mul_property_data' => [ + 'left_field' => 'revision_id', + 'field' => 'revision_id', + ], ], $revision_base_data['table']['join']); $this->assertFalse(isset($data['data_table'])); + + $this->assertEquals('entity_test_mul_property_data', $revision_field_data['id']['relationship']['base']); + $this->assertEquals('id', $revision_field_data['id']['relationship']['base field']); + $this->assertEquals('entity_test_mul_property_data', $revision_field_data['revision_id']['relationship']['base']); + $this->assertEquals('revision_id', $revision_field_data['revision_id']['relationship']['base field']); } /** @@ -341,15 +355,24 @@ public function testRevisionTableWithRevisionDataTable() { ], $revision_field_data['table']['join']); $revision_base_data = $data['entity_test_mulrev_revision']; - $this->assertCount(1, $revision_base_data['table']['join']); + $this->assertCount(2, $revision_base_data['table']['join']); $this->assertEquals([ 'entity_test_mulrev_property_revision' => [ 'left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER', ], + 'entity_test_mulrev_field_data' => [ + 'left_field' => 'revision_id', + 'field' => 'revision_id', + ], ], $revision_base_data['table']['join']); $this->assertFalse(isset($data['data_table'])); + + $this->assertEquals('entity_test_mulrev_field_data', $revision_field_data['id']['relationship']['base']); + $this->assertEquals('id', $revision_field_data['id']['relationship']['base field']); + $this->assertEquals('entity_test_mulrev_field_data', $revision_field_data['revision_id']['relationship']['base']); + $this->assertEquals('revision_id', $revision_field_data['revision_id']['relationship']['base field']); } /** @@ -583,6 +606,11 @@ public function testRevisionTableFields() { $this->assertNumericField($data['entity_test_mulrev_property_revision']['id']); $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['id'], 'id'); + $this->assertEquals('entity_test_mulrev_property_data', $data['entity_test_mulrev_property_revision']['id']['relationship']['base']); + $this->assertEquals('id', $data['entity_test_mulrev_property_revision']['id']['relationship']['base field']); + $this->assertEquals('entity_test_mulrev_property_data', $data['entity_test_mulrev_property_revision']['revision_id']['relationship']['base']); + $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['revision_id']['relationship']['base field']); + $this->assertLanguageField($data['entity_test_mulrev_property_revision']['langcode']); $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['langcode'], 'langcode'); $this->assertEquals('Translation language', $data['entity_test_mulrev_property_revision']['langcode']['title']); diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php index cd925a9b845c2b9e50bacffb6d0f3278ab8c6110..b5407369121788fb6b996667d0321e4a67a76bff 100644 --- a/core/modules/views/views.post_update.php +++ b/core/modules/views/views.post_update.php @@ -87,3 +87,10 @@ function views_post_update_sort_identifier(?array &$sandbox = NULL): void { return $view_config_updater->needsSortFieldIdentifierUpdate($view); }); } + +/** + * Clear caches due to adding a relationship from revision table to base table. + */ +function views_post_update_provide_revision_table_relationship() { + // Empty post-update hook. +}