From 073cc74c4d11acfd394595724f368d804b8d9711 Mon Sep 17 00:00:00 2001
From: Francesco Placella <plach@183211.no-reply.drupal.org>
Date: Fri, 26 Apr 2019 00:30:46 +0200
Subject: [PATCH] Issue #2987956 by mariancalinro, amateescu, vijaycs85, mheip,
 mallezie: Entity queries with sorting and ordering are not working in a
 non-default workspace

---
 .../workspaces/src/EntityQuery/Query.php      | 29 +++------------
 .../workspaces/src/EntityQuery/QueryTrait.php | 14 +++++++
 .../src/Kernel/WorkspaceIntegrationTest.php   | 37 ++++++++++++++++++-
 3 files changed, 55 insertions(+), 25 deletions(-)

diff --git a/core/modules/workspaces/src/EntityQuery/Query.php b/core/modules/workspaces/src/EntityQuery/Query.php
index f91aa6afbc66..471c1d87a481 100644
--- a/core/modules/workspaces/src/EntityQuery/Query.php
+++ b/core/modules/workspaces/src/EntityQuery/Query.php
@@ -13,17 +13,6 @@ class Query extends BaseQuery {
     prepare as traitPrepare;
   }
 
-  /**
-   * Stores the SQL expressions used to build the SQL query.
-   *
-   * The array is keyed by the expression alias and the values are the actual
-   * expressions.
-   *
-   * @var array
-   *   An array of expressions.
-   */
-  protected $sqlExpressions = [];
-
   /**
    * {@inheritdoc}
    */
@@ -42,21 +31,15 @@ public function prepare() {
       // relationship, and, as a consequence, the revision ID field is no longer
       // a simple SQL field but an expression.
       $this->sqlFields = [];
-      $this->sqlExpressions[$revision_field] = "COALESCE(workspace_association.target_entity_revision_id, base_table.$revision_field)";
-      $this->sqlExpressions[$id_field] = "base_table.$id_field";
+      $this->sqlQuery->addExpression("COALESCE(workspace_association.target_entity_revision_id, base_table.$revision_field)", $revision_field);
+      $this->sqlQuery->addExpression("base_table.$id_field", $id_field);
+
+      $this->sqlGroupBy['workspace_association.target_entity_revision_id'] = 'workspace_association.target_entity_revision_id';
+      $this->sqlGroupBy["base_table.$id_field"] = "base_table.$id_field";
+      $this->sqlGroupBy["base_table.$revision_field"] = "base_table.$revision_field";
     }
 
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function finish() {
-    foreach ($this->sqlExpressions as $alias => $expression) {
-      $this->sqlQuery->addExpression($expression, $alias);
-    }
-    return parent::finish();
-  }
-
 }
diff --git a/core/modules/workspaces/src/EntityQuery/QueryTrait.php b/core/modules/workspaces/src/EntityQuery/QueryTrait.php
index a102469fb5c6..da906bc7191e 100644
--- a/core/modules/workspaces/src/EntityQuery/QueryTrait.php
+++ b/core/modules/workspaces/src/EntityQuery/QueryTrait.php
@@ -69,4 +69,18 @@ public function prepare() {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function isSimpleQuery() {
+    // We declare that this is not a simple query in
+    // \Drupal\workspaces\EntityQuery\QueryTrait::prepare(), but that's not
+    // enough because the parent method can return TRUE in some circumstances.
+    if ($this->sqlQuery->getMetaData('active_workspace_id')) {
+      return FALSE;
+    }
+
+    return parent::isSimpleQuery();
+  }
+
 }
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
index 160c0050575d..c58b6642e63c 100644
--- a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
@@ -44,6 +44,13 @@ class WorkspaceIntegrationTest extends KernelTestBase {
    */
   protected $createdTimestamp;
 
+  /**
+   * An array of nodes created before installing the Workspaces module.
+   *
+   * @var \Drupal\node\NodeInterface[]
+   */
+  protected $nodes = [];
+
   /**
    * {@inheritdoc}
    */
@@ -83,8 +90,8 @@ protected function setUp() {
     // Create two nodes, a published and an unpublished one, so we can test the
     // behavior of the module with default/existing content.
     $this->createdTimestamp = \Drupal::time()->getRequestTime();
-    $this->createNode(['title' => 'live - 1 - r1 - published', 'created' => $this->createdTimestamp++, 'status' => TRUE]);
-    $this->createNode(['title' => 'live - 2 - r2 - unpublished', 'created' => $this->createdTimestamp++, 'status' => FALSE]);
+    $this->nodes[] = $this->createNode(['title' => 'live - 1 - r1 - published', 'created' => $this->createdTimestamp++, 'status' => TRUE]);
+    $this->nodes[] = $this->createNode(['title' => 'live - 2 - r2 - unpublished', 'created' => $this->createdTimestamp++, 'status' => FALSE]);
   }
 
   /**
@@ -338,6 +345,32 @@ public function testWorkspaces() {
     $this->assertEmpty($workspace_publisher->getDifferringRevisionIdsOnSource());
   }
 
+  /**
+   * Tests entity query overrides without any conditions.
+   */
+  public function testEntityQueryWithoutConditions() {
+    $this->initializeWorkspacesModule();
+    $this->switchToWorkspace('stage');
+
+    // Add a workspace-specific revision to a pre-existing node.
+    $this->nodes[1]->title->value = 'stage - 2 - r3 - published';
+    $this->nodes[1]->save();
+
+    $query = $this->entityTypeManager->getStorage('node')->getQuery();
+    $query->sort('nid');
+    $query->pager(1);
+    $result = $query->execute();
+
+    $this->assertSame([1 => '1'], $result);
+
+    $query = $this->entityTypeManager->getStorage('node')->getQuery();
+    $query->sort('nid', 'DESC');
+    $query->pager(10);
+    $result = $query->execute();
+
+    $this->assertSame([3 => '2', 1 => '1'], $result);
+  }
+
   /**
    * Tests the Entity Query relationship API with workspaces.
    */
-- 
GitLab