APIv4 - Don't assume the identifier field for a table is named 'id'
authorColeman Watts <coleman@civicrm.org>
Thu, 24 Jun 2021 19:36:23 +0000 (15:36 -0400)
committerColeman Watts <coleman@civicrm.org>
Fri, 25 Jun 2021 18:02:15 +0000 (14:02 -0400)
APIv4 getInfo() now returns the name of the "id_field" for any entity.
This modifies the selectQuery so that `get` actions rely on that metadata.

Civi/Api4/CustomValue.php
Civi/Api4/Query/Api4SelectQuery.php

index acb10d88d8b90279b1b182232dc5a4e69a6d711f..bd1705d06592314eabd3c39e1cab5c6c2a26ac7b 100644 (file)
@@ -142,6 +142,7 @@ class CustomValue {
       'class' => __CLASS__,
       'type' => ['CustomValue'],
       'searchable' => 'secondary',
+      'id_field' => 'id',
       'see' => [
         'https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/#multiple-record-fieldsets',
         '\Civi\Api4\CustomGroup',
index 052c0c0aa4c9c92e1745e7bc6884a438d7321486..99940efefd39478de2aea3f95351422bd481d85f 100644 (file)
@@ -88,7 +88,8 @@ class Api4SelectQuery {
     $this->api = $apiGet;
 
     // Always select ID of main table unless grouping by something else
-    $this->forceSelectId = !$this->isAggregateQuery() || $this->getGroupBy() === ['id'];
+    $id = $this->getIdField($this->getEntity());
+    $this->forceSelectId = !$this->isAggregateQuery() || $this->getGroupBy() === [$id];
 
     // Build field lists
     foreach ($this->api->entityFields() as $field) {
@@ -203,7 +204,8 @@ class Api4SelectQuery {
     }
     else {
       if ($this->forceSelectId) {
-        $select = array_merge(['id'], $select);
+        $id = $this->getIdField($this->getEntity());
+        $select = array_merge([$id], $select);
       }
 
       // Expand the superstar 'custom.*' to select all fields in all custom groups
@@ -228,8 +230,10 @@ class Api4SelectQuery {
       foreach ($wildFields as $wildField) {
         $pos = array_search($wildField, array_values($select));
         // If the joined_entity.id isn't in the fieldspec already, autoJoinFK will attempt to add the entity.
-        $idField = substr($wildField, 0, strrpos($wildField, '.')) . '.id';
-        $this->autoJoinFK($idField);
+        $fkField = substr($wildField, 0, strrpos($wildField, '.'));
+        $fkEntity = $this->getField($fkField)['fk_entity'] ?? NULL;
+        $id = $fkEntity ? $this->getIdField($fkEntity) : 'id';
+        $this->autoJoinFK($fkField . ".$id");
         $matches = $this->selectMatchingFields($wildField);
         array_splice($select, $pos, 1, $matches);
       }
@@ -272,6 +276,14 @@ class Api4SelectQuery {
     return SelectUtil::getMatchingFields($pattern, array_keys($availableFields));
   }
 
+  /**
+   * @param $entityName
+   * @return string
+   */
+  private function getIdField($entityName) {
+    return CoreUtil::getApiClass($entityName)::getInfo()['id_field'];
+  }
+
   /**
    * Add WHERE clause to query
    */