api/v3 - _civicrm_api3_basic_create - Define fallback if BAO::create() is missing
authorTim Otten <totten@civicrm.org>
Thu, 4 Jul 2013 16:03:57 +0000 (09:03 -0700)
committerTim Otten <totten@civicrm.org>
Thu, 4 Jul 2013 16:40:49 +0000 (09:40 -0700)
api/v3/utils.php

index 4c8ea1782f1bbc6ea91f0f7958e23d882630ebe4..38e2d06809c9a9d77e019bd571e3f7d153db32cb 100644 (file)
@@ -947,22 +947,28 @@ function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $
 function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
 
   $args = array(&$params);
-  if(!empty($entity)){
+  if (!empty($entity)) {
     $ids = array($entity => CRM_Utils_Array::value('id', $params));
     $args[] = &$ids;
   }
+
   if (method_exists($bao_name, 'create')) {
     $fct = 'create';
+    $fct_name = $bao_name . '::' . $fct;
+    $bao = call_user_func_array(array($bao_name, $fct), $args);
   }
   elseif (method_exists($bao_name, 'add')) {
     $fct = 'add';
+    $fct_name = $bao_name . '::' . $fct;
+    $bao = call_user_func_array(array($bao_name, $fct), $args);
   }
-  if (!isset($fct)) {
-    return civicrm_api3_create_error('Entity not created, missing create or add method for ' . $bao_name);
+  else {
+    $fct_name = '_civicrm_api3_basic_create_fallback';
+    $bao = _civicrm_api3_basic_create_fallback($bao_name, $params);
   }
-  $bao = call_user_func_array(array($bao_name, $fct), $args);
+
   if (is_null($bao)) {
-    return civicrm_api3_create_error('Entity not created ' . $bao_name . '::' . $fct);
+    return civicrm_api3_create_error('Entity not created (' . $fct_name . ')');
   }
   else {
     $values = array();
@@ -971,6 +977,34 @@ 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 array $params
+ * @return CRM_Core_DAO|NULL an instance of the BAO
+ */
+function _civicrm_api3_basic_create_fallback($bao_name, &$params) {
+  $entityName = CRM_Core_DAO_AllCoreTables::getBriefName(get_parent_class($bao_name));
+  if (empty($entityName)) {
+    throw new API_Exception("Class \"$bao_name\" does not map to an entity name", "unmapped_class_to_entity", array(
+      '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 $bao_name();
+  $instance->copyValues($params);
+  $instance->save();
+  CRM_Utils_Hook::post($hook, $entityName, $instance->id, $instance);
+
+  return $instance;
+}
+
 /**
  * Function to do a 'standard' api del - when the api is only doing a $bao::del then use this
  * if api::del doesn't exist it will try DAO delete method