[BUGFIX] Allow cloning of the QueryBuilder 24/53424/4
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Sat, 8 Jul 2017 16:08:12 +0000 (18:08 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sat, 15 Jul 2017 16:44:39 +0000 (18:44 +0200)
In order to be able to implement pagination
it has to be possible to clone QueryBuilder.

Doctrine query builder already supports cloning,
so it's just about allowing it in our wrapper.

Resolves: #81822
Releases: master, 8.7
Change-Id: I059bdc51d1181cac08a3d9f30de174b025c6e89d
Reviewed-on: https://review.typo3.org/53424
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Wolfgang Klinger <wolfgang@wazum.com>
Tested-by: Wolfgang Klinger <wolfgang@wazum.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Database/Query/QueryBuilder.php
typo3/sysext/core/Tests/Unit/Database/Query/QueryBuilderTest.php

index ffcce83..1a900c3 100644 (file)
@@ -1092,4 +1092,14 @@ class QueryBuilder
 
         return $originalWhereConditions;
     }
+
+    /**
+     * Deep clone of the QueryBuilder
+     * @see \Doctrine\DBAL\Query\QueryBuilder::__clone()
+     */
+    public function __clone()
+    {
+        $this->concreteQueryBuilder = clone $this->concreteQueryBuilder;
+        $this->restrictionContainer = clone $this->restrictionContainer;
+    }
 }
index df677e6..14b016c 100644 (file)
@@ -1162,4 +1162,74 @@ class QueryBuilderTest extends UnitTestCase
         $result = $this->callInaccessibleMethod($subject, 'unquoteSingleIdentifier', $input);
         $this->assertEquals($expected, $result);
     }
+
+    /**
+     * @test
+     */
+    public function cloningQueryBuilderClonesConcreteQueryBuilder()
+    {
+        $clonedQueryBuilder = clone $this->subject;
+        self::assertNotSame($this->subject->getConcreteQueryBuilder(), $clonedQueryBuilder->getConcreteQueryBuilder());
+    }
+
+    /**
+     * @test
+     */
+    public function changingClonedQueryBuilderDoesNotInfluenceSourceOne()
+    {
+        $GLOBALS['TCA']['pages']['ctrl'] = [
+            'tstamp' => 'tstamp',
+            'versioningWS' => true,
+            'delete' => 'deleted',
+            'crdate' => 'crdate',
+            'enablecolumns' => [
+                'disabled' => 'hidden',
+            ],
+        ];
+
+        $this->connection->quoteIdentifier(Argument::cetera())
+            ->willReturnArgument(0);
+        $this->connection->quoteIdentifiers(Argument::cetera())
+            ->willReturnArgument(0);
+        $this->connection->getExpressionBuilder()
+            ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
+
+        $concreteQueryBuilder = GeneralUtility::makeInstance(
+            \Doctrine\DBAL\Query\QueryBuilder::class,
+            $this->connection->reveal()
+        );
+
+        $subject = GeneralUtility::makeInstance(
+            QueryBuilder::class,
+            $this->connection->reveal(),
+            null,
+            $concreteQueryBuilder
+        );
+
+        $subject->select('*')
+            ->from('pages')
+            ->where('uid=1');
+
+        $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
+        $this->assertSame($expectedSQL, $subject->getSQL());
+
+        $clonedQueryBuilder = clone $subject;
+        //just after cloning both query builders should return the same sql
+        $this->assertSame($expectedSQL, $clonedQueryBuilder->getSQL());
+
+        //change cloned QueryBuilder
+        $clonedQueryBuilder->count('*');
+        $expectedCountSQL = 'SELECT COUNT(*) FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
+        $this->assertSame($expectedCountSQL, $clonedQueryBuilder->getSQL());
+
+        //check if the original QueryBuilder has not changed
+        $this->assertSame($expectedSQL, $subject->getSQL());
+
+        //change restrictions in the original QueryBuilder and check if cloned has changed
+        $subject->getRestrictions()->removeAll()->add(new DeletedRestriction());
+        $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND (pages.deleted = 0)';
+        $this->assertSame($expectedSQL, $subject->getSQL());
+
+        $this->assertSame($expectedCountSQL, $clonedQueryBuilder->getSQL());
+    }
 }