From ab4317677ea71aa7b9c6c80e4d5ec582f2763db5 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Fri, 30 Nov 2018 10:23:57 +0000
Subject: [PATCH] Issue #2977276 by Sam152, ergonlogic, amateescu, jibran,
 catch, greggmarshall: Node views integration that joins revisions to the
 default entity fails to consider langcode, resulting in duplicate rows

---
 core/modules/node/node.post_update.php        |  7 ++++
 core/modules/node/src/NodeViewsData.php       | 10 +++++
 .../views.view.test_node_revision_nid.yml     | 22 ++++++++++
 .../views.view.test_node_revision_vid.yml     | 23 ++++++++++
 .../Views/RevisionRelationshipsTest.php       | 42 +++++++++++++++++--
 5 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/core/modules/node/node.post_update.php b/core/modules/node/node.post_update.php
index 43e3cd6acc3..913137757c2 100644
--- a/core/modules/node/node.post_update.php
+++ b/core/modules/node/node.post_update.php
@@ -27,3 +27,10 @@ function node_post_update_configure_status_field_widget() {
     ])->save();
   }
 }
+
+/**
+ * Clear caches due to updated views data.
+ */
+function node_post_update_node_revision_views_data() {
+  // Empty post-update hook.
+}
diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php
index eb72bfafb73..ef7d5d3efad 100644
--- a/core/modules/node/src/NodeViewsData.php
+++ b/core/modules/node/src/NodeViewsData.php
@@ -216,6 +216,10 @@ class NodeViewsData extends EntityViewsData {
     $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' => [
@@ -228,6 +232,12 @@ class NodeViewsData extends EntityViewsData {
         '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'];
 
diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_nid.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_nid.yml
index 179e1401c1d..8c5d4cb4b2c 100644
--- a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_nid.yml
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_nid.yml
@@ -44,6 +44,13 @@ display:
           plugin_id: field
           entity_type: node
           entity_field: nid
+        langcode:
+          id: langcode
+          table: node_field_revision
+          field: langcode
+          plugin_id: field
+          entity_type: node
+          entity_field: langcode
       arguments:
         nid:
           id: nid
@@ -61,6 +68,21 @@ display:
           plugin_id: field
           entity_type: node
           entity_field: vid
+        langcode:
+          id: langcode
+          table: node_field_revision
+          field: langcode
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: DESC
+          exposed: false
+          expose:
+            label: ''
+          entity_type: node
+          entity_field: langcode
+          plugin_id: standard
+      display_extenders: {  }
     display_plugin: default
     display_title: Master
     id: default
diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_vid.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_vid.yml
index a2783a56d74..3c9aac56f28 100644
--- a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_vid.yml
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_vid.yml
@@ -44,6 +44,13 @@ display:
           plugin_id: field
           entity_type: node
           entity_field: nid
+        langcode:
+          id: langcode
+          table: node_field_revision
+          field: langcode
+          entity_type: node
+          entity_field: langcode
+          plugin_id: field
       arguments:
         nid:
           id: nid
@@ -52,6 +59,22 @@ display:
           plugin_id: node_nid
           entity_type: node
           entity_field: nid
+      display_extenders: {  }
+      sorts:
+        langcode:
+          id: langcode
+          table: node_field_revision
+          field: langcode
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          entity_type: node
+          entity_field: langcode
+          plugin_id: standard
     display_plugin: default
     display_title: Master
     id: default
diff --git a/core/modules/node/tests/src/Kernel/Views/RevisionRelationshipsTest.php b/core/modules/node/tests/src/Kernel/Views/RevisionRelationshipsTest.php
index e47bdd038b3..b21610c5fde 100644
--- a/core/modules/node/tests/src/Kernel/Views/RevisionRelationshipsTest.php
+++ b/core/modules/node/tests/src/Kernel/Views/RevisionRelationshipsTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\node\Kernel\Views;
 
+use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Entity\Node;
 use Drupal\node\Entity\NodeType;
 use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
@@ -20,7 +21,12 @@ class RevisionRelationshipsTest extends ViewsKernelTestBase {
    *
    * @var array
    */
-  public static $modules = ['node' , 'node_test_views'];
+  public static $modules = [
+    'node',
+    'node_test_views',
+    'language',
+    'content_translation',
+  ];
 
   /**
    * {@inheritdoc}
@@ -33,6 +39,8 @@ class RevisionRelationshipsTest extends ViewsKernelTestBase {
     $this->installEntitySchema('user');
     $this->installEntitySchema('node');
 
+    ConfigurableLanguage::createFromLangcode('fr')->save();
+
     ViewTestData::createTestViews(get_class($this), ['node_test_views']);
   }
 
@@ -51,16 +59,22 @@ class RevisionRelationshipsTest extends ViewsKernelTestBase {
     $type->save();
     $node = Node::create(['type' => 'page', 'title' => 'test', 'uid' => 1]);
     $node->save();
+
+    // Add a translation.
+    $translation = $node->addTranslation('fr', $node->toArray());
+    $translation->save();
     // Create revision of the node.
     $node->setNewRevision(TRUE);
     $node->save();
+
     $column_map = [
       'vid' => 'vid',
       'node_field_data_node_field_revision_nid' => 'node_node_revision_nid',
       'nid_1' => 'nid_1',
+      'node_field_revision_langcode' => 'node_field_revision_langcode',
     ];
 
-    // Here should be two rows.
+    // Here should be two rows for each translation.
     $view_nid = Views::getView('test_node_revision_nid');
     $this->executeView($view_nid, [$node->id()]);
     $resultset_nid = [
@@ -68,17 +82,32 @@ class RevisionRelationshipsTest extends ViewsKernelTestBase {
         'vid' => '1',
         'node_node_revision_nid' => '1',
         'nid_1' => '1',
+        'node_field_revision_langcode' => 'fr',
+      ],
+      [
+        'vid' => '1',
+        'node_node_revision_nid' => '1',
+        'nid_1' => '1',
+        'node_field_revision_langcode' => 'en',
       ],
       [
         'vid' => '2',
         'node_revision_nid' => '1',
         'node_node_revision_nid' => '1',
         'nid_1' => '1',
+        'node_field_revision_langcode' => 'fr',
+      ],
+      [
+        'vid' => '2',
+        'node_revision_nid' => '1',
+        'node_node_revision_nid' => '1',
+        'nid_1' => '1',
+        'node_field_revision_langcode' => 'en',
       ],
     ];
     $this->assertIdenticalResultset($view_nid, $resultset_nid, $column_map);
 
-    // There should be only one row with active revision 2.
+    // There should be one row with active revision 2 for each translation.
     $view_vid = Views::getView('test_node_revision_vid');
     $this->executeView($view_vid, [$node->id()]);
     $resultset_vid = [
@@ -86,6 +115,13 @@ class RevisionRelationshipsTest extends ViewsKernelTestBase {
         'vid' => '2',
         'node_node_revision_nid' => '1',
         'nid_1' => '1',
+        'node_field_revision_langcode' => 'en',
+      ],
+      [
+        'vid' => '2',
+        'node_node_revision_nid' => '1',
+        'nid_1' => '1',
+        'node_field_revision_langcode' => 'fr',
       ],
     ];
     $this->assertIdenticalResultset($view_vid, $resultset_vid, $column_map);