[TASK] Doctrine: Add support for column aliases in select() 20/47820/2
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Wed, 20 Apr 2016 17:11:46 +0000 (19:11 +0200)
committerWouter Wolters <typo3@wouterwolters.nl>
Wed, 27 Apr 2016 20:34:08 +0000 (22:34 +0200)
Add support for selecting a column under a different identifier (alias)
when building a SELECT query.

Releases: master
Resolves: #75823
Change-Id: I3464c9d848c4892ea57b92cc1257654ff9e14110
Reviewed-on: https://review.typo3.org/47820
Reviewed-by: Michael Oehlhof <typo3@oehlhof.de>
Tested-by: Michael Oehlhof <typo3@oehlhof.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
typo3/sysext/core/Classes/Database/Query/QueryBuilder.php
typo3/sysext/core/Tests/Unit/Database/Query/QueryBuilderTest.php

index c6f6218..576ec2c 100644 (file)
@@ -923,18 +923,32 @@ class QueryBuilder
      * @param array $input
      *
      * @return array
+     * @throws \InvalidArgumentException
      */
     public function quoteIdentifiersForSelect(array $input): array
     {
-        // The SQL * operator must not be quoted. As it can only occur either by itself
-        // or preceded by a tablename (tablename.*) check if the last character of a select
-        // expression is the * and quote only prepended table name. In all other cases the
-        // full expression is being quoted.
         foreach ($input as &$select) {
-            if (substr($select, -2) === '.*') {
-                $select = $this->quoteIdentifier(substr($select, 0, -2)) . '.*';
-            } elseif ($select !== '*') {
-                $select = $this->quoteIdentifier($select);
+            list($fieldName, $alias, $suffix) = GeneralUtility::trimExplode(' AS ', $select, 3);
+            if (!empty($suffix)) {
+                throw new \InvalidArgumentException(
+                    'QueryBuilder::quoteIdentifiersForSelect() could not parse the input "' . $input . '"',
+                    1461170686
+                );
+            }
+
+            // The SQL * operator must not be quoted. As it can only occur either by itself
+            // or preceded by a tablename (tablename.*) check if the last character of a select
+            // expression is the * and quote only prepended table name. In all other cases the
+            // full expression is being quoted.
+            if (substr($fieldName, -2) === '.*') {
+                $select = $this->quoteIdentifier(substr($fieldName, 0, -2)) . '.*';
+            } elseif ($fieldName !== '*') {
+                $select = $this->quoteIdentifier($fieldName);
+            }
+
+            // Quote the alias for the current fieldName, if given
+            if (!empty($alias)) {
+                $select .= ' AS ' . $this->quoteIdentifier($alias);
             }
         }
         return $input;
index 35a547d..03c8e4a 100644 (file)
@@ -279,6 +279,75 @@ class QueryBuilderTest extends UnitTestCase
         $this->subject->select('aField', 'anotherField');
     }
 
+    public function quoteIdentifiersForSelectDataProvider()
+    {
+        return [
+            'fieldName' => [
+                'fieldName',
+                '"fieldName"',
+            ],
+            'tableName.fieldName' => [
+                'tableName.fieldName',
+                '"tableName"."fieldName"',
+            ],
+            'tableName.*' => [
+                'tableName.*',
+                '"tableName".*',
+            ],
+            '*' => [
+                '*',
+                '*',
+            ],
+            'fieldName AS anotherFieldName' => [
+                'fieldName AS anotherFieldName',
+                '"fieldName" AS "anotherFieldName"',
+            ],
+            'tableName.fieldName AS anotherFieldName' => [
+                'tableName.fieldName AS anotherFieldName',
+                '"tableName"."fieldName" AS "anotherFieldName"',
+            ],
+            'tableName.fieldName AS anotherTable.anotherFieldName' => [
+                'tableName.fieldName AS anotherTable.anotherFieldName',
+                '"tableName"."fieldName" AS "anotherTable"."anotherFieldName"',
+            ],
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider quoteIdentifiersForSelectDataProvider
+     * @param string $identifier
+     * @param string $expectedResult
+     */
+    public function quoteIdentifiersForSelect($identifier, $expectedResult)
+    {
+        $this->connection->quoteIdentifier(Argument::cetera())->will(
+            function ($args) {
+                $platform = new MockPlatform();
+
+                return $platform->quoteIdentifier($args[0]);
+            }
+        );
+
+        $this->assertSame([$expectedResult], $this->subject->quoteIdentifiersForSelect([$identifier]));
+    }
+
+    /**
+     * @test
+     * @expectedException \InvalidArgumentException
+     */
+    public function quoteIdentifiersForSelectWithInvalidAlias()
+    {
+        $this->connection->quoteIdentifier(Argument::cetera())->will(
+            function ($args) {
+                $platform = new MockPlatform();
+
+                return $platform->quoteIdentifier($args[0]);
+            }
+        );
+        $this->subject->quoteIdentifiersForSelect(['aField AS anotherField,someField AS someThing']);
+    }
+
     /**
      * @test
      */