From adb45e1d7bcb6a445c0e66dbd936092a72a52cde Mon Sep 17 00:00:00 2001
From: Johannes Kasberger <johannes.kasberger@reelworx.at>
Date: Tue, 21 Feb 2017 14:27:56 +0100
Subject: [PATCH] [BUGFIX] Extbase: correct handling of mm relations

This change fixes a regression after the doctrine migration and additionally
fixes a wrong join condition which is also present in version 7

Resolves: #79931
Resolves: #79932
Releases: master
Change-Id: I04a4ce174fb1da3baca9af8ba771a7db70d9a884
Reviewed-on: https://review.typo3.org/51782
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
---
 .../Generic/Storage/Typo3DbQueryParser.php    | 12 +++---
 .../Domain/Repository/PostRepository.php      | 13 +++++++
 .../Persistence/Fixtures/category-mm.xml      | 10 +++++
 .../Functional/Persistence/RelationTest.php   | 39 +++++++++++++++++++
 4 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php
index 9aba64c24cd0..51810ae641ff 100644
--- a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php
+++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php
@@ -954,9 +954,12 @@ class Typo3DbQueryParser
             $relationTableName = $columnMap->getRelationTableName();
             $relationTableAlias = $relationTableAlias = $this->getUniqueAlias($relationTableName, $fullPropertyPath . '_mm');
 
-            $joinConditionExpression = $this->queryBuilder->expr()->eq(
-                $tableName . '.uid',
-                $relationTableAlias . '.' . $columnMap->getParentKeyFieldName()
+            $joinConditionExpression = $this->queryBuilder->expr()->andX(
+                $this->queryBuilder->expr()->eq(
+                    $tableName . '.uid',
+                    $relationTableAlias . '.' . $columnMap->getParentKeyFieldName()
+                ),
+                $this->getAdditionalMatchFieldsStatement($this->queryBuilder->expr(), $columnMap, $relationTableAlias, $realTableName)
             );
             $this->queryBuilder->leftJoin($tableName, $relationTableName, $relationTableAlias, $joinConditionExpression);
             $joinConditionExpression = $this->queryBuilder->expr()->eq(
@@ -964,9 +967,6 @@ class Typo3DbQueryParser
                 $childTableAlias . '.uid'
             );
             $this->queryBuilder->leftJoin($relationTableAlias, $childTableName, $childTableAlias, $joinConditionExpression);
-            $this->queryBuilder->andWhere(
-                $this->getAdditionalMatchFieldsStatement($this->queryBuilder->expr(), $columnMap, $relationTableAlias, $realTableName)
-            );
             $this->unionTableAliasCache[] = $childTableAlias;
             $this->queryBuilder->addGroupBy($this->tableName . '.uid');
         } else {
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php
index 6ca57c01f3b2..f51a4e538391 100644
--- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php
@@ -14,6 +14,8 @@ namespace ExtbaseTeam\BlogExample\Domain\Repository;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Persistence\QueryInterface;
+
 /**
  * A repository for blog posts
  *
@@ -148,4 +150,15 @@ class PostRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
             )
             ->execute();
     }
+
+    public function findAllSortedByCategory(array $uids)
+    {
+        $q = $this->createQuery();
+        $q->matching($q->in('uid', $uids));
+        $q->setOrderings([
+            'categories.title' => QueryInterface::ORDER_ASCENDING,
+            'uid' => QueryInterface::ORDER_ASCENDING,
+        ]);
+        return $q->execute();
+    }
 }
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/category-mm.xml b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/category-mm.xml
index a92727532be0..785e287813a8 100644
--- a/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/category-mm.xml
+++ b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/category-mm.xml
@@ -46,6 +46,16 @@
 		<sorting_foreign>2</sorting_foreign>
 	</sys_category_record_mm>
 
+	<!-- some bogus records to test MM_match_fields -->
+	<sys_category_record_mm>
+		<uid_local>4</uid_local>
+		<uid_foreign>5</uid_foreign>
+		<tablenames>tx_my_extension</tablenames>
+		<fieldname>categories</fieldname>
+		<sorting>1</sorting>
+		<sorting_foreign>2</sorting_foreign>
+	</sys_category_record_mm>
+
 	<!-- blog 1 gets categories 1,2,3 -->
 	<sys_category_record_mm>
 		<uid_local>1</uid_local>
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/RelationTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/RelationTest.php
index 6cc153d3123e..09aefcd94810 100644
--- a/typo3/sysext/extbase/Tests/Functional/Persistence/RelationTest.php
+++ b/typo3/sysext/extbase/Tests/Functional/Persistence/RelationTest.php
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Extbase\Tests\Functional\Persistence;
  * The TYPO3 project - inspiring people to share!
  */
 
+use ExtbaseTeam\BlogExample\Domain\Model\Post;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -1009,4 +1010,42 @@ class RelationTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTes
         $blogRepository->update($this->blog);
         $this->persistentManager->persistAll();
     }
+
+    public function ensureCorrectPostOrderingByCategoryTitleDataProvider()
+    {
+        return [
+            'Post with no category and post with category' => [
+                [2, 3],
+                [3, 2]
+            ],
+            'Posts with category and Post with category and bogus category' => [
+                [2, 1],
+                [1, 2]
+            ],
+            'Posts bogus category and post with category' => [
+                [5, 2],
+                [5, 2]
+            ],
+        ];
+    }
+
+    /**
+     * This test covers the case when data is ordered by criteria that is MM related with matchFields involved
+     * on the relation table. (post <-> sys_category_mm <-> sys_category)
+     *
+     * @test
+     * @dataProvider ensureCorrectPostOrderingByCategoryTitleDataProvider
+     */
+    public function ensureCorrectPostOrderingByCategoryTitle(array $uids, array $expected)
+    {
+        /** @var \ExtbaseTeam\BlogExample\Domain\Repository\PostRepository $postRepository */
+        $postRepository = $this->objectManager->get(\ExtbaseTeam\BlogExample\Domain\Repository\PostRepository::class);
+        $posts = $postRepository->findAllSortedByCategory($uids)->toArray();
+        $result = [];
+        /** @var Post $post */
+        foreach ($posts as $post) {
+            $result[] = $post->getUid();
+        }
+        $this->assertSame($expected, $result);
+    }
 }
-- 
GitLab