From 2ee9afab7db97b4be11ee3d83d7672fa7a07ae44 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 19 Mar 2020 14:04:56 -0400 Subject: [PATCH] Add DAO::writeRecord and DAO::deleteRecord methods --- CRM/Core/DAO.php | 56 +++++++++++++++++++++ Civi/Api4/Generic/DAODeleteAction.php | 17 ++----- Civi/Api4/Generic/Traits/DAOActionTrait.php | 24 +-------- api/v3/utils.php | 27 ++-------- 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php index 0075a2536161..77ee8b49d609 100644 --- a/CRM/Core/DAO.php +++ b/CRM/Core/DAO.php @@ -794,6 +794,62 @@ public static function getAttribute($class, $fieldName = NULL) { 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. * diff --git a/Civi/Api4/Generic/DAODeleteAction.php b/Civi/Api4/Generic/DAODeleteAction.php index 3e0135f8991c..79bc911c4af3 100644 --- a/Civi/Api4/Generic/DAODeleteAction.php +++ b/Civi/Api4/Generic/DAODeleteAction.php @@ -54,8 +54,9 @@ protected function deleteObjects($items) { $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 @@ protected function deleteObjects($items) { } 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; diff --git a/Civi/Api4/Generic/Traits/DAOActionTrait.php b/Civi/Api4/Generic/Traits/DAOActionTrait.php index fc4fe9d262b3..065e8a08847e 100644 --- a/Civi/Api4/Generic/Traits/DAOActionTrait.php +++ b/Civi/Api4/Generic/Traits/DAOActionTrait.php @@ -166,7 +166,7 @@ protected function writeObjects($items) { $createResult = $baoName::$method($item); } else { - $createResult = $this->genericCreateMethod($item); + $createResult = $baoName::writeRecord($item); } if (!$createResult) { @@ -180,26 +180,6 @@ protected function writeObjects($items) { 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 @@ protected function checkContactPermissions($baoName, $item) { 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); } } diff --git a/api/v3/utils.php b/api/v3/utils.php index f2dabc16dc74..3c9ded7475df 100644 --- a/api/v3/utils.php +++ b/api/v3/utils.php @@ -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); } /**