Add DAO::writeRecord and DAO::deleteRecord methods
authorColeman Watts <coleman@civicrm.org>
Thu, 19 Mar 2020 18:04:56 +0000 (14:04 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 19 Mar 2020 18:12:37 +0000 (14:12 -0400)
CRM/Core/DAO.php
Civi/Api4/Generic/DAODeleteAction.php
Civi/Api4/Generic/Traits/DAOActionTrait.php
api/v3/utils.php

index 0075a25361611f6fae5082065fe9dff89e9dcd63..77ee8b49d609d460482c7b185db0b952ddf33788 100644 (file)
@@ -794,6 +794,62 @@ class CRM_Core_DAO extends DB_DataObject {
     return NULL;
   }
 
+  /**
+   * Create or update a record from supplied params.
+   *
+   * If 'id' is supplied, an existing record will be updated
+   * Otherwise a new record will be created.
+   *
+   * @param array $record
+   * @return CRM_Core_DAO
+   * @throws CRM_Core_Exception
+   */
+  public static function writeRecord(array $record) {
+    $hook = empty($record['id']) ? 'create' : 'edit';
+    $className = CRM_Core_DAO_AllCoreTables::getCanonicalClassName(static::class);
+    if ($className === 'CRM_Core_DAO') {
+      throw new CRM_Core_Exception('Function writeRecord must be called on a subclass of CRM_Core_DAO');
+    }
+    $entityName = CRM_Core_DAO_AllCoreTables::getBriefName($className);
+
+    \CRM_Utils_Hook::pre($hook, $entityName, $record['id'] ?? NULL, $record);
+    $instance = new $className();
+    $instance->copyValues($record);
+    $instance->save();
+    \CRM_Utils_Hook::post($hook, $entityName, $instance->id, $instance);
+
+    return $instance;
+  }
+
+  /**
+   * Delete a record from supplied params.
+   *
+   * @param array $record
+   *   'id' is required.
+   * @return CRM_Core_DAO
+   * @throws CRM_Core_Exception
+   */
+  public static function deleteRecord(array $record) {
+    $className = CRM_Core_DAO_AllCoreTables::getCanonicalClassName(static::class);
+    if ($className === 'CRM_Core_DAO') {
+      throw new CRM_Core_Exception('Function deleteRecord must be called on a subclass of CRM_Core_DAO');
+    }
+    $entityName = CRM_Core_DAO_AllCoreTables::getBriefName($className);
+    if (empty($record['id'])) {
+      throw new CRM_Core_Exception("Cannot delete {$entityName} with no id.");
+    }
+
+    CRM_Utils_Hook::pre('delete', $entityName, $record['id'], $record);
+    $instance = new $className();
+    $instance->id = $record['id'];
+    if (!$instance->delete()) {
+      throw new CRM_Core_Exception("Could not delete {$entityName} id {$record['id']}");
+    }
+    CRM_Utils_Hook::post('delete', $entityName, $record['id'], $instance);
+
+    return $instance;
+  }
+
   /**
    * Check if there is a record with the same name in the db.
    *
index 3e0135f8991cbcb291f5aaf1c9f625edebba5417..79bc911c4af38f50e74a700b7971011c9299cfcf 100644 (file)
@@ -54,8 +54,9 @@ class DAODeleteAction extends AbstractBatchAction {
     $baoName = $this->getBaoName();
 
     if ($this->getCheckPermissions()) {
-      foreach ($items as $item) {
-        $this->checkContactPermissions($baoName, $item);
+      foreach (array_keys($items) as $key) {
+        $items[$key]['check_permissions'] = TRUE;
+        $this->checkContactPermissions($baoName, $items[$key]);
       }
     }
 
@@ -73,16 +74,8 @@ class DAODeleteAction extends AbstractBatchAction {
     }
     else {
       foreach ($items as $item) {
-        $bao = new $baoName();
-        $bao->id = $item['id'];
-        // delete it
-        $action_result = $bao->delete();
-        if ($action_result) {
-          $ids[] = ['id' => $item['id']];
-        }
-        else {
-          throw new \API_Exception("Could not delete {$this->getEntityName()} id {$item['id']}");
-        }
+        $baoName::deleteRecord($item);
+        $ids[] = ['id' => $item['id']];
       }
     }
     return $ids;
index fc4fe9d262b3a426c0a6cc39c15456e4ab2b9016..065e8a08847e7b615def57b6067f39dd12bd117c 100644 (file)
@@ -166,7 +166,7 @@ trait DAOActionTrait {
         $createResult = $baoName::$method($item);
       }
       else {
-        $createResult = $this->genericCreateMethod($item);
+        $createResult = $baoName::writeRecord($item);
       }
 
       if (!$createResult) {
@@ -180,26 +180,6 @@ trait DAOActionTrait {
     return $result;
   }
 
-  /**
-   * Fallback when a BAO does not contain create or add functions
-   *
-   * @param $params
-   * @return mixed
-   */
-  private function genericCreateMethod($params) {
-    $baoName = $this->getBaoName();
-    $hook = empty($params['id']) ? 'create' : 'edit';
-
-    \CRM_Utils_Hook::pre($hook, $this->getEntityName(), $params['id'] ?? NULL, $params);
-    /** @var \CRM_Core_DAO $instance */
-    $instance = new $baoName();
-    $instance->copyValues($params);
-    $instance->save();
-    \CRM_Utils_Hook::post($hook, $this->getEntityName(), $instance->id, $instance);
-
-    return $instance;
-  }
-
   /**
    * @param array $params
    * @param int $entityId
@@ -281,7 +261,7 @@ trait DAOActionTrait {
     else {
       // Fixme: decouple from v3
       require_once 'api/v3/utils.php';
-      _civicrm_api3_check_edit_permissions($baoName, ['check_permissions' => 1] + $item);
+      _civicrm_api3_check_edit_permissions($baoName, $item);
     }
   }
 
index f2dabc16dc740b347e97d9b78e92840373ad8a69..3c9ded7475df6eeb0bc78e615708c0a4072dcd5c 100644 (file)
@@ -1325,10 +1325,7 @@ function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
 /**
  * For BAO's which don't have a create() or add() functions, use this fallback implementation.
  *
- * @fixme There's an intuitive sense that this behavior should be defined somehow in the BAO/DAO class
- * structure. In practice, that requires a fair amount of refactoring and/or kludgery.
- *
- * @param string $bao_name
+ * @param string|CRM_Core_DAO $bao_name
  * @param array $params
  *
  * @throws API_Exception
@@ -1336,26 +1333,8 @@ function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
  * @return CRM_Core_DAO|NULL
  *   An instance of the BAO
  */
-function _civicrm_api3_basic_create_fallback($bao_name, &$params) {
-  $dao_name = get_parent_class($bao_name);
-  if ($dao_name === 'CRM_Core_DAO' || !$dao_name) {
-    $dao_name = $bao_name;
-  }
-  $entityName = CRM_Core_DAO_AllCoreTables::getBriefName($dao_name);
-  if (empty($entityName)) {
-    throw new API_Exception("Class \"$bao_name\" does not map to an entity name", "unmapped_class_to_entity", [
-      'class_name' => $bao_name,
-    ]);
-  }
-  $hook = empty($params['id']) ? 'create' : 'edit';
-
-  CRM_Utils_Hook::pre($hook, $entityName, CRM_Utils_Array::value('id', $params), $params);
-  $instance = new $dao_name();
-  $instance->copyValues($params);
-  $instance->save();
-  CRM_Utils_Hook::post($hook, $entityName, $instance->id, $instance);
-
-  return $instance;
+function _civicrm_api3_basic_create_fallback($bao_name, $params) {
+  return $bao_name::writeRecord($params);
 }
 
 /**