APIv4 - Allow field aliases in ORDER BY clause
authorColeman Watts <coleman@civicrm.org>
Fri, 12 Feb 2021 16:06:28 +0000 (11:06 -0500)
committerColeman Watts <coleman@civicrm.org>
Mon, 15 Feb 2021 02:22:36 +0000 (21:22 -0500)
Civi/Api4/Query/Api4SelectQuery.php
tests/phpunit/api/v4/Action/SqlFunctionTest.php

index 49a3760b3141c2e53203364d276bed75fa88a2dc..073e36ac29e8f82fd575644dd10993413ff1f6cc 100644 (file)
@@ -275,19 +275,32 @@ class Api4SelectQuery {
       if ($dir !== 'ASC' && $dir !== 'DESC') {
         throw new \API_Exception("Invalid sort direction. Cannot order by $item $dir");
       }
-      $expr = $this->getExpression($item);
-      $column = $expr->render($this->apiFieldSpec);
-
-      // Use FIELD() function to sort on pseudoconstant values
-      $suffix = strstr($item, ':');
-      if ($suffix && $expr->getType() === 'SqlField') {
-        $field = $this->getField($item);
-        $options = FormattingUtil::getPseudoconstantList($field, substr($suffix, 1));
-        if ($options) {
-          asort($options);
-          $column = "FIELD($column,'" . implode("','", array_keys($options)) . "')";
+
+      try {
+        $expr = $this->getExpression($item);
+        $column = $expr->render($this->apiFieldSpec);
+
+        // Use FIELD() function to sort on pseudoconstant values
+        $suffix = strstr($item, ':');
+        if ($suffix && $expr->getType() === 'SqlField') {
+          $field = $this->getField($item);
+          $options = FormattingUtil::getPseudoconstantList($field, substr($suffix, 1));
+          if ($options) {
+            asort($options);
+            $column = "FIELD($column,'" . implode("','", array_keys($options)) . "')";
+          }
         }
       }
+      // If the expression could not be rendered, it might be a field alias
+      catch (\API_Exception $e) {
+        if (!empty($this->selectAliases[$item])) {
+          $column = '`' . $item . '`';
+        }
+        else {
+          throw new \API_Exception("Invalid field '{$item}'");
+        }
+      }
+
       $this->query->orderBy("$column $dir");
     }
   }
index 27815be6c3b96aa76bf5e6daa84876792c7b7cbe..a4ecd8d11f0bf582b4fa7bf4d775058cd12a85fd 100644 (file)
@@ -57,6 +57,7 @@ class SqlFunctionTest extends UnitTestCase {
       ->addSelect('MAX(total_amount)')
       ->addSelect('MIN(total_amount)')
       ->addSelect('COUNT(*) AS count')
+      ->addOrderBy('average')
       ->execute()
       ->first();
     $this->assertTrue(250.0 === $agg['average']);