Merge pull request #16475 from JMAConsulting/core_1577
[civicrm-core.git] / api / api.php
index 61501b6afd883d0816f8bc94cebea33f0b4ca1ff..1a70bc3921cb83182598e84da4c5e23a4d0702b8 100644 (file)
@@ -24,14 +24,37 @@ function civicrm_api(string $entity = NULL, string $action, array $params, $extr
 }
 
 /**
- * Procedural wrapper for the OO api version 4.
+ * CiviCRM API version 4.
  *
- * @param string $entity
- * @param string $action
- * @param array $params
- * @param string|int $index
- *   If $index is a string, the results array will be indexed by that key.
- *   If $index is an integer, only the result at that index will be returned.
+ * This API (Application Programming Interface) is used to access and manage data in CiviCRM.
+ *
+ * APIv4 is the latest stable version.
+ *
+ * @see https://docs.civicrm.org/dev/en/latest/api/v4/usage/
+ *
+ * @param string $entity Name of the CiviCRM entity to access.
+ *   All entity names are capitalized CamelCase, e.g. `ContributionPage`.
+ *   Most entities correspond to a database table (e.g. `Contact` is the table `civicrm_contact`).
+ *   For a complete list of available entities, call `civicrm_api4('Entity', 'get');`
+ *
+ * @param string $action The "verb" of the api call.
+ *   For a complete list of actions for a given entity (e.g. `Contact`), call `civicrm_api4('Contact', 'getActions');`
+ *
+ * @param array $params An array of API input keyed by parameter name.
+ *   The easiest way to discover all available parameters is to visit the API Explorer on your CiviCRM site.
+ *   The API Explorer is listed in the CiviCRM menu under Support -> Developer.
+ *
+ * @param string|int|array $index Controls the Result array format.
+ *   By default the api Result contains a non-associative array of data. Passing an $index tells the api to
+ *   automatically reformat the array, depending on the variable type passed:
+ *   - **Integer:** return a single result array;
+ *     e.g. `$index = 0` will return the first result, 1 will return the second, and -1 will return the last.
+ *   - **String:** index the results by a field value;
+ *     e.g. `$index = "name"` will return an associative array with the field 'name' as keys.
+ *   - **Non-associative array:** return a single value from each result;
+ *     e.g. `$index = ['title']` will return a non-associative array of strings - the 'title' field from each result.
+ *   - **Associative array:** a combination of the previous two modes;
+ *     e.g. `$index = ['name' => 'title']` will return an array of strings - the 'title' field keyed by the 'name' field.
  *
  * @return \Civi\Api4\Generic\Result
  * @throws \API_Exception
@@ -39,18 +62,43 @@ function civicrm_api(string $entity = NULL, string $action, array $params, $extr
  */
 function civicrm_api4(string $entity, string $action, array $params = [], $index = NULL) {
   $apiCall = \Civi\Api4\Utils\ActionUtil::getAction($entity, $action);
+  $indexField = $index && is_string($index) && !CRM_Utils_Rule::integer($index) ? $index : NULL;
+  $removeIndexField = FALSE;
+
+  // If index field is not part of the select query, we add it here and remove it below
+  if ($indexField && !empty($params['select']) && is_array($params['select']) && !\Civi\Api4\Utils\SelectUtil::isFieldSelected($indexField, $params['select'])) {
+    $params['select'][] = $indexField;
+    $removeIndexField = TRUE;
+  }
   foreach ($params as $name => $param) {
     $setter = 'set' . ucfirst($name);
     $apiCall->$setter($param);
   }
+
+  if ($index && is_array($index)) {
+    $indexCol = reset($index);
+    $indexField = key($index);
+    if (property_exists($apiCall, 'select')) {
+      $apiCall->setSelect([$indexCol]);
+      if ($indexField && $indexField != $indexCol) {
+        $apiCall->addSelect($indexField);
+      }
+    }
+  }
+
   $result = $apiCall->execute();
 
   // Index results by key
-  if ($index && is_string($index) && !CRM_Utils_Rule::integer($index)) {
-    $result->indexBy($index);
+  if ($indexField) {
+    $result->indexBy($indexField);
+    if ($removeIndexField) {
+      foreach ($result as $key => $value) {
+        unset($result[$key][$indexField]);
+      }
+    }
   }
   // Return result at index
-  if (CRM_Utils_Rule::integer($index)) {
+  elseif (CRM_Utils_Rule::integer($index)) {
     $item = $result->itemAt($index);
     if (is_null($item)) {
       throw new \API_Exception("Index $index not found in api results");
@@ -60,7 +108,9 @@ function civicrm_api4(string $entity, string $action, array $params = [], $index
       return $item;
     }
     $result->exchangeArray($item);
-
+  }
+  if (!empty($indexCol)) {
+    $result->exchangeArray($result->column($indexCol));
   }
   return $result;
 }