Browse Source

Add callable support to `Query::orderAsc()` and `Query::orderDesc()`.

ndm2 5 years ago
parent
commit
524a45a6bb
2 changed files with 62 additions and 2 deletions
  1. 12 2
      src/Database/Query.php
  2. 50 0
      tests/TestCase/Database/QueryTest.php

+ 12 - 2
src/Database/Query.php

@@ -1202,7 +1202,7 @@ class Query implements ExpressionInterface, IteratorAggregate
      * Order fields are not suitable for use with user supplied data as they are
      * not sanitized by the query builder.
      *
-     * @param string|\Cake\Database\Expression\QueryExpression $field The field to order on.
+     * @param string|\Cake\Database\Expression\QueryExpression|callable $field The field to order on.
      * @param bool $overwrite Whether or not to reset the order clauses.
      * @return $this
      */
@@ -1218,6 +1218,11 @@ class Query implements ExpressionInterface, IteratorAggregate
         if (!$this->_parts['order']) {
             $this->_parts['order'] = new OrderByExpression();
         }
+
+        if ($this->_parts['order']->isCallable($field)) {
+            $field = $field($this->newExpr(), $this);
+        }
+
         $this->_parts['order']->add(new OrderClauseExpression($field, 'ASC'));
 
         return $this;
@@ -1232,7 +1237,7 @@ class Query implements ExpressionInterface, IteratorAggregate
      * Order fields are not suitable for use with user supplied data as they are
      * not sanitized by the query builder.
      *
-     * @param string|\Cake\Database\Expression\QueryExpression $field The field to order on.
+     * @param string|\Cake\Database\Expression\QueryExpression|callable $field The field to order on.
      * @param bool $overwrite Whether or not to reset the order clauses.
      * @return $this
      */
@@ -1248,6 +1253,11 @@ class Query implements ExpressionInterface, IteratorAggregate
         if (!$this->_parts['order']) {
             $this->_parts['order'] = new OrderByExpression();
         }
+
+        if ($this->_parts['order']->isCallable($field)) {
+            $field = $field($this->newExpr(), $this);
+        }
+
         $this->_parts['order']->add(new OrderClauseExpression($field, 'DESC'));
 
         return $this;

+ 50 - 0
tests/TestCase/Database/QueryTest.php

@@ -2110,6 +2110,31 @@ class QueryTest extends TestCase
             ['id' => 3],
         ];
         $this->assertEquals($expected, $result);
+
+        $query = new Query($this->connection);
+        $query->select(['id'])
+            ->from('articles')
+            ->orderAsc(function (QueryExpression $exp, Query $query) {
+                return $exp->addCase(
+                    [$query->newExpr()->add(['author_id' => 1])],
+                    [1, $query->identifier('id')],
+                    ['integer', null]
+                );
+            })
+            ->orderAsc('id');
+        $sql = $query->sql();
+        $result = $query->execute()->fetchAll('assoc');
+        $expected = [
+            ['id' => 1],
+            ['id' => 3],
+            ['id' => 2],
+        ];
+        $this->assertEquals($expected, $result);
+        $this->assertQuotedQuery(
+            'SELECT <id> FROM <articles> ORDER BY CASE WHEN <author_id> = :c0 THEN :param1 ELSE <id> END ASC, <id> ASC',
+            $sql,
+            !$this->autoQuote
+        );
     }
 
     /**
@@ -2150,6 +2175,31 @@ class QueryTest extends TestCase
             ['id' => 1],
         ];
         $this->assertEquals($expected, $result);
+
+        $query = new Query($this->connection);
+        $query->select(['id'])
+            ->from('articles')
+            ->orderDesc(function (QueryExpression $exp, Query $query) {
+                return $exp->addCase(
+                    [$query->newExpr()->add(['author_id' => 1])],
+                    [1, $query->identifier('id')],
+                    ['integer', null]
+                );
+            })
+            ->orderDesc('id');
+        $sql = $query->sql();
+        $result = $query->execute()->fetchAll('assoc');
+        $expected = [
+            ['id' => 2],
+            ['id' => 3],
+            ['id' => 1],
+        ];
+        $this->assertEquals($expected, $result);
+        $this->assertQuotedQuery(
+            'SELECT <id> FROM <articles> ORDER BY CASE WHEN <author_id> = :c0 THEN :param1 ELSE <id> END DESC, <id> DESC',
+            $sql,
+            !$this->autoQuote
+        );
     }
 
     /**