APIv4 - Preserve order when expanding select wildcards
authorColeman Watts <coleman@civicrm.org>
Thu, 26 Mar 2020 20:52:10 +0000 (16:52 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 26 Mar 2020 20:55:42 +0000 (16:55 -0400)
Civi/Api4/Generic/AbstractGetAction.php
tests/phpunit/api/v4/Action/BasicActionsTest.php

index e9f892c2af7d56be795098b495872faebf16e55a..d82e7071b1e6f0328d65c8afae9a774d14e242da 100644 (file)
@@ -80,12 +80,15 @@ abstract class AbstractGetAction extends AbstractQueryAction {
    * @throws \API_Exception
    */
   protected function expandSelectClauseWildcards() {
-    foreach ($this->select as $item) {
-      if (strpos($item, '*') !== FALSE && strpos($item, '.') === FALSE) {
-        $this->select = array_diff($this->select, [$item]);
-        $this->select = array_unique(array_merge($this->select, SelectUtil::getMatchingFields($item, array_column($this->entityFields(), 'name'))));
-      }
+    $wildFields = array_filter($this->select, function($item) {
+      return strpos($item, '*') !== FALSE && strpos($item, '.') === FALSE;
+    });
+    foreach ($wildFields as $item) {
+      $pos = array_search($item, array_values($this->select));
+      $matches = SelectUtil::getMatchingFields($item, array_column($this->entityFields(), 'name'));
+      array_splice($this->select, $pos, 1, $matches);
     }
+    $this->select = array_unique($this->select);
   }
 
   /**
index ace6f05bf871090440beea68063a63851f986961..21b181f7d444c1e9af7de18834c8d9549005e012 100644 (file)
@@ -197,4 +197,25 @@ class BasicActionsTest extends UnitTestCase {
     $this->assertTrue($isFieldSelected->invoke($get, 'group'));
   }
 
+  public function testWildcardSelect() {
+    MockBasicEntity::delete()->addWhere('id', '>', 0)->execute();
+
+    $records = [
+      ['group' => 'one', 'color' => 'red', 'shape' => 'round', 'size' => 'med', 'weight' => 10],
+      ['group' => 'two', 'color' => 'blue', 'shape' => 'round', 'size' => 'med', 'weight' => 20],
+    ];
+    MockBasicEntity::save()->setRecords($records)->execute();
+
+    foreach (MockBasicEntity::get()->addSelect('*')->execute() as $result) {
+      ksort($result);
+      $this->assertEquals(['color', 'group', 'id', 'shape', 'size', 'weight'], array_keys($result));
+    }
+
+    $result = MockBasicEntity::get()
+      ->addSelect('*e', 'weig*ht')
+      ->execute()
+      ->first();
+    $this->assertEquals(['shape', 'size', 'weight'], array_keys($result));
+  }
+
 }