Merge pull request #14667 from hoegrammer/master
[civicrm-core.git] / Civi / Api4 / Generic / BasicReplaceAction.php
index 1c71536279f48af1596aeca001c2b3426a3939ea..cb06ec096e096bd14bd89f968a6512d43892e352 100644 (file)
 
 namespace Civi\Api4\Generic;
 
-use Civi\API\Exception\NotImplementedException;
-use Civi\Api4\Utils\ActionUtil;
-
 /**
- * Given a set of records, will appropriately update the database.
+ * Replaces an existing set of $ENTITIES with a new one.
+ *
+ * This will select a group of existing $ENTITIES based on the `where` parameter.
+ * Each will be compared with the $ENTITIES passed in as `records`:
  *
- * @method $this setRecords(array $records) Array of records.
- * @method $this addRecord($record) Add a record to update.
+ *  - $ENTITIES in `records` that don't already exist will be created.
+ *  - Existing $ENTITIES that are included in `records` will be updated.
+ *  - Existing $ENTITIES that are omitted from `records` will be deleted.
+ *
+ * @method $this setRecords(array $records) Set array of records.
  * @method array getRecords()
- * @method $this setDefaults(array $defaults) Array of defaults.
- * @method $this addDefault($name, $value) Add a default value.
+ * @method $this setDefaults(array $defaults) Set array of defaults.
  * @method array getDefaults()
  * @method $this setReload(bool $reload) Specify whether complete objects will be returned after saving.
  * @method bool getReload()
@@ -39,9 +41,9 @@ use Civi\Api4\Utils\ActionUtil;
 class BasicReplaceAction extends AbstractBatchAction {
 
   /**
-   * Array of records.
+   * Array of $ENTITY records.
    *
-   * Should be in the same format as returned by Get.
+   * Should be in the same format as returned by `Get`.
    *
    * @var array
    * @required
@@ -51,18 +53,23 @@ class BasicReplaceAction extends AbstractBatchAction {
   /**
    * Array of default values.
    *
-   * Will be merged into $records before saving.
+   * These defaults will be merged into every $ENTITY in `records` before saving.
+   * Values set in `records` will override these defaults if set in both places,
+   * but updating existing $ENTITIES will overwrite current values with these defaults.
+   *
+   * **Note:** Values from the `where` clause that use the `=` operator are _also_ treated as default values;
+   * those do not need to be repeated here.
    *
    * @var array
    */
   protected $defaults = [];
 
   /**
-   * Reload records after saving.
+   * Reload $ENTITIES after saving.
    *
-   * By default this api typically returns partial records containing only the fields
-   * that were updated. Set reload to TRUE to do an additional lookup after saving
-   * to return complete records.
+   * By default this action typically returns partial records containing only the fields
+   * that were updated. Set `reload` to `true` to do an additional lookup after saving
+   * to return complete values for every $ENTITY.
    *
    * @var bool
    */
@@ -91,36 +98,13 @@ class BasicReplaceAction extends AbstractBatchAction {
     $idField = $this->getSelect()[0];
     $toDelete = array_diff_key(array_column($items, NULL, $idField), array_flip(array_filter(\CRM_Utils_Array::collect($idField, $this->records))));
 
-    // Try to delegate to the Save action
-    try {
-      $saveAction = ActionUtil::getAction($this->getEntityName(), 'save');
-      $saveAction
-        ->setCheckPermissions($this->getCheckPermissions())
-        ->setReload($this->reload)
-        ->setRecords($this->records)
-        ->setDefaults($this->defaults);
-      $result->exchangeArray((array) $saveAction->execute());
-    }
-    // Fall back on Create/Update if Save doesn't exist
-    catch (NotImplementedException $e) {
-      foreach ($this->records as $record) {
-        $record += $this->defaults;
-        if (!empty($record[$idField])) {
-          $result[] = civicrm_api4($this->getEntityName(), 'update', [
-            'reload' => $this->reload,
-            'where' => [[$idField, '=', $record[$idField]]],
-            'values' => $record,
-            'checkPermissions' => $this->getCheckPermissions(),
-          ])->first();
-        }
-        else {
-          $result[] = civicrm_api4($this->getEntityName(), 'create', [
-            'values' => $record,
-            'checkPermissions' => $this->getCheckPermissions(),
-          ])->first();
-        }
-      }
-    }
+    $saveAction = \Civi\API\Request::create($this->getEntityName(), 'save', ['version' => 4]);
+    $saveAction
+      ->setCheckPermissions($this->getCheckPermissions())
+      ->setReload($this->reload)
+      ->setRecords($this->records)
+      ->setDefaults($this->defaults);
+    $result->exchangeArray((array) $saveAction->execute());
 
     if ($toDelete) {
       $result->deleted = (array) civicrm_api4($this->getEntityName(), 'delete', [
@@ -130,4 +114,25 @@ class BasicReplaceAction extends AbstractBatchAction {
     }
   }
 
+  /**
+   * Set default value for a field.
+   * @param string $fieldName
+   * @param mixed $defaultValue
+   * @return $this
+   */
+  public function addDefault(string $fieldName, $defaultValue) {
+    $this->defaults[$fieldName] = $defaultValue;
+    return $this;
+  }
+
+  /**
+   * Add one or more records
+   * @param array ...$records
+   * @return $this
+   */
+  public function addRecord(array ...$records) {
+    $this->records = array_merge($this->records, $records);
+    return $this;
+  }
+
 }