Merge remote-tracking branch 'origin/4.5' into 4.5-master-2015-02-24-17-24-05
[civicrm-core.git] / api / v3 / utils.php
index 0e04b694b7cae66b654f25db2bb6c9b12ca5fc5a..8c053187a42dae298536f4949a6f20307df4d5c0 100644 (file)
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
-*/
+ */
 
 /**
- * File for CiviCRM APIv3 utilitity functions
+ * CiviCRM APIv3 utility functions.
  *
  * @package CiviCRM_APIv3
- * @subpackage API_utils
- *
- * @copyright CiviCRM LLC (c) 2004-2014
- * @version $Id: utils.php 30879 2010-11-22 15:45:55Z shot $
- *
  */
 
 /**
- * Initialize CiviCRM - should be run at the start of each API function
+ * Initialize CiviCRM - should be run at the start of each API function.
  */
 function _civicrm_api3_initialize() {
   require_once 'CRM/Core/ClassLoader.php';
@@ -46,7 +41,7 @@ function _civicrm_api3_initialize() {
 }
 
 /**
- * Wrapper Function for civicrm_verify_mandatory to make it simple to pass either / or fields for checking
+ * Wrapper Function for civicrm_verify_mandatory to make it simple to pass either / or fields for checking.
  *
  * @param array $params
  *   Array of fields to check.
@@ -64,7 +59,7 @@ function civicrm_api3_verify_one_mandatory($params, $daoName = NULL, $keyoptions
 }
 
 /**
- * check mandatory fields are included
+ * Check mandatory fields are included.
  *
  * @param array $params
  *   Array of fields to check.
@@ -73,6 +68,8 @@ function civicrm_api3_verify_one_mandatory($params, $daoName = NULL, $keyoptions
  * @param array $keys
  *   List of required fields. A value can be an array denoting that either this or that is required.
  * @param bool $verifyDAO
+ *
+ * @throws \API_Exception
  */
 function civicrm_api3_verify_mandatory($params, $daoName = NULL, $keys = array(), $verifyDAO = TRUE) {
 
@@ -124,9 +121,11 @@ function civicrm_api3_verify_mandatory($params, $daoName = NULL, $keys = array()
 }
 
 /**
+ * Create error array.
  *
- * @param $msg
+ * @param string $msg
  * @param array $data
+ *
  * @return array
  */
 function civicrm_api3_create_error($msg, $data = array()) {
@@ -135,7 +134,8 @@ function civicrm_api3_create_error($msg, $data = array()) {
   // we will show sql to privileged user only (not sure of a specific
   // security hole here but seems sensible - perhaps should apply to the trace as well?)
   if (isset($data['sql']) && CRM_Core_Permission::check('Administer CiviCRM')) {
-    $data['debug_information'] = $data['sql']; // Isn't this redundant?
+    // Isn't this redundant?
+    $data['debug_information'] = $data['sql'];
   }
   else {
     unset($data['sql']);
@@ -144,7 +144,7 @@ function civicrm_api3_create_error($msg, $data = array()) {
 }
 
 /**
- * Format array in result output styple
+ * Format array in result output style.
  *
  * @param array|int $values values generated by API operation (the result)
  * @param array $params
@@ -163,12 +163,15 @@ function civicrm_api3_create_error($msg, $data = array()) {
  */
 function civicrm_api3_create_success($values = 1, $params = array(), $entity = NULL, $action = NULL, &$dao = NULL, $extraReturnValues = array()) {
   $result = array();
+  $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity);
+  // TODO: This shouldn't be necessary but this fn sometimes gets called with lowercase entity
+  $entity = _civicrm_api_get_camel_name($entity);
   $result['is_error'] = 0;
   //lets set the ['id'] field if it's not set & we know what the entity is
-  if (is_array($values) && !empty($entity) && $action != 'getfields') {
+  if (is_array($values) && $entity && $action != 'getfields') {
     foreach ($values as $key => $item) {
-      if (empty($item['id']) && !empty($item[$entity . "_id"])) {
-        $values[$key]['id'] = $item[$entity . "_id"];
+      if (empty($item['id']) && !empty($item[$lowercase_entity . "_id"])) {
+        $values[$key]['id'] = $item[$lowercase_entity . "_id"];
       }
       if (!empty($item['financial_type_id'])) {
         //4.3 legacy handling
@@ -197,7 +200,24 @@ function civicrm_api3_create_success($values = 1, $params = array(), $entity = N
       $allFields = array_keys($apiFields['values']);
     }
     $paramFields = array_keys($params);
-    $undefined = array_diff($paramFields, $allFields, array_keys($_COOKIE), array('action', 'entity', 'debug', 'version', 'check_permissions', 'IDS_request_uri', 'IDS_user_agent', 'return', 'sequential', 'rowCount', 'option_offset', 'option_limit', 'custom', 'option_sort', 'options', 'prettyprint'));
+    $undefined = array_diff($paramFields, $allFields, array_keys($_COOKIE), array(
+      'action',
+      'entity',
+      'debug',
+      'version',
+      'check_permissions',
+      'IDS_request_uri',
+      'IDS_user_agent',
+      'return',
+      'sequential',
+      'rowCount',
+      'option_offset',
+      'option_limit',
+      'custom',
+      'option_sort',
+      'options',
+      'prettyprint',
+      ));
     if ($undefined) {
       $result['undefined_fields'] = array_merge($undefined);
     }
@@ -233,21 +253,23 @@ function civicrm_api3_create_success($values = 1, $params = array(), $entity = N
     $result['values'] = $values;
   }
   if (!empty($params['options']['metadata'])) {
-    // we've made metadata an array but only supporting 'fields' atm
+    // We've made metadata an array but only supporting 'fields' atm.
     if (in_array('fields', (array) $params['options']['metadata']) && $action !== 'getfields') {
-      $fields = civicrm_api3($entity, 'getfields', array('action' => substr($action, 0, 3) == 'get' ? 'get' : 'create'));
+      $fields = civicrm_api3($entity, 'getfields', array(
+        'action' => substr($action, 0, 3) == 'get' ? 'get' : 'create',
+      ));
       $result['metadata']['fields'] = $fields['values'];
     }
   }
-  // Report deprecations
+  // Report deprecations.
   $deprecated = _civicrm_api3_deprecation_check($entity, $result);
-  // Always report "update" action as deprecated
+  // Always report "update" action as deprecated.
   if (!is_string($deprecated) && ($action == 'getactions' || $action == 'update')) {
     $deprecated = ((array) $deprecated) + array('update' => 'The "update" action is deprecated. Use "create" with an id instead.');
   }
   if ($deprecated) {
-    // Metadata-level deprecations or wholesale entity deprecations
-    if ($entity == 'entity' || $action == 'getactions' || is_string($deprecated)) {
+    // Metadata-level deprecations or wholesale entity deprecations.
+    if ($entity == 'Entity' || $action == 'getactions' || is_string($deprecated)) {
       $result['deprecated'] = $deprecated;
     }
     // Action-specific deprecations
@@ -259,8 +281,10 @@ function civicrm_api3_create_success($values = 1, $params = array(), $entity = N
 }
 
 /**
- * Load the DAO of the entity
+ * Load the DAO of the entity.
+ *
  * @param $entity
+ *
  * @return bool
  */
 function _civicrm_api3_load_DAO($entity) {
@@ -273,11 +297,13 @@ function _civicrm_api3_load_DAO($entity) {
 }
 
 /**
- * return the DAO of the function or Entity
+ * Return the DAO of the function or Entity.
+ *
  * @param string $name
  *   Either a function of the api (civicrm_{entity}_create or the entity name.
  *   return the DAO name to manipulate this function
  *   eg. "civicrm_api3_contact_create" or "Contact" will return "CRM_Contact_BAO_Contact"
+ *
  * @return mixed|string
  */
 function _civicrm_api3_get_DAO($name) {
@@ -287,7 +313,7 @@ function _civicrm_api3_get_DAO($name) {
     $name = substr($name, 13, $last - 13);
   }
 
-  $name = _civicrm_api_get_camel_name($name, 3);
+  $name = _civicrm_api_get_camel_name($name);
 
   if ($name == 'Individual' || $name == 'Household' || $name == 'Organization') {
     $name = 'Contact';
@@ -341,11 +367,13 @@ function _civicrm_api3_get_DAO($name) {
 }
 
 /**
- * return the DAO of the function or Entity
+ * Return the DAO of the function or Entity.
+ *
  * @param string $name
  *   Is either a function of the api (civicrm_{entity}_create or the entity name.
  *   return the DAO name to manipulate this function
  *   eg. "civicrm_contact_create" or "Contact" will return "CRM_Contact_BAO_Contact"
+ *
  * @return mixed
  */
 function _civicrm_api3_get_BAO($name) {
@@ -364,7 +392,8 @@ function _civicrm_api3_get_BAO($name) {
 }
 
 /**
- *  Recursive function to explode value-separated strings into arrays
+ * Recursive function to explode value-separated strings into arrays.
+ *
  * @param $values
  */
 function _civicrm_api3_separate_values(&$values) {
@@ -374,7 +403,8 @@ function _civicrm_api3_separate_values(&$values) {
       _civicrm_api3_separate_values($value);
     }
     elseif (is_string($value)) {
-      if ($key == 'case_type_id') {// this is to honor the way case API was originally written
+      // This is to honor the way case API was originally written.
+      if ($key == 'case_type_id') {
         $value = trim(str_replace($sp, ',', $value), ',');
       }
       elseif (strpos($value, $sp) !== FALSE) {
@@ -385,12 +415,14 @@ function _civicrm_api3_separate_values(&$values) {
 }
 
 /**
- * This is a legacy wrapper for api_store_values which will check the suitable fields using getfields
- * rather than DAO->fields
+ * This is a legacy wrapper for api_store_values.
  *
- * Getfields has handling for how to deal with uniquenames which dao->fields doesn't
+ * It checks suitable fields using getfields rather than DAO->fields.
+ *
+ * Getfields has handling for how to deal with unique names which dao->fields doesn't
  *
  * Note this is used by BAO type create functions - eg. contribution
+ *
  * @param string $entity
  * @param array $params
  * @param array $values
@@ -401,6 +433,7 @@ function _civicrm_api3_filter_fields_for_bao($entity, &$params, &$values) {
   _civicrm_api3_store_values($fields, $params, $values);
 }
 /**
+ * Store values.
  *
  * @param array $fields
  * @param array $params
@@ -422,7 +455,9 @@ function _civicrm_api3_store_values(&$fields, &$params, &$values) {
 }
 
 /**
- * The API supports 2 types of get requestion. The more complex uses the BAO query object.
+ * Get function for query object api.
+ *
+ * The API supports 2 types of get request. The more complex uses the BAO query object.
  *  This is a generic function for those functions that call it
  *
  *  At the moment only called by contact we should extend to contribution &
@@ -431,6 +466,7 @@ function _civicrm_api3_store_values(&$fields, &$params, &$values) {
  *
  * Ideally this would be merged with _civicrm_get_query_object but we need to resolve differences in what the
  * 2 variants call
+ *
  * @param $entity
  * @param array $params
  *   As passed into api get or getcount function.
@@ -442,10 +478,10 @@ function _civicrm_api3_store_values(&$fields, &$params, &$values) {
  * @return array
  */
 function _civicrm_api3_get_using_query_object($entity, $params, $additional_options = array(), $getCount = NULL) {
-
+  $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity);
   // Convert id to e.g. contact_id
-  if (empty($params[$entity . '_id']) && isset($params['id'])) {
-    $params[$entity . '_id'] = $params['id'];
+  if (empty($params[$lowercase_entity . '_id']) && isset($params['id'])) {
+    $params[$lowercase_entity . '_id'] = $params['id'];
   }
   unset($params['id']);
 
@@ -466,7 +502,7 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti
     // we will filter query object against getfields
     $fields = civicrm_api($entity, 'getfields', array('version' => 3, 'action' => 'get'));
     // we need to add this in as earlier in this function 'id' was unset in favour of $entity_id
-    $fields['values'][$entity . '_id'] = array();
+    $fields['values'][$lowercase_entity . '_id'] = array();
     $varsToFilter = array('returnProperties', 'inputParams');
     foreach ($varsToFilter as $varToFilter) {
       if (!is_array($$varToFilter)) {
@@ -490,6 +526,10 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti
     $returnProperties = NULL;
   }
 
+  if (substr($sort, 0, 2) == 'id') {
+    $sort = $lowercase_entity . "_" . $sort;
+  }
+
   $newParams = CRM_Contact_BAO_Query::convertFormValues($inputParams);
   foreach ($newParams as &$newParam) {
     if ($newParam[1] == '='  && is_array($newParam[2])) {
@@ -501,7 +541,6 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti
         $newParam[2] = $sqlFilter;
       }
     }
-
   }
 
   $skipPermissions = !empty($params['check_permissions']) ? 0 : 1;
@@ -526,13 +565,15 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti
 }
 
 /**
- * get dao query object based on input params
+ * Get dao query object based on input params.
+ *
  * Ideally this would be merged with _civicrm_get_using_query_object but we need to resolve differences in what the
  * 2 variants call
  *
  * @param array $params
  * @param string $mode
  * @param string $entity
+ *
  * @return array
  *   [CRM_Core_DAO|CRM_Contact_BAO_Query]
  */
@@ -567,20 +608,21 @@ function _civicrm_api3_get_query_object($params, $mode, $entity) {
 }
 
 /**
- * Function transfers the filters being passed into the DAO onto the params object
+ * Function transfers the filters being passed into the DAO onto the params object.
+ *
  * @param CRM_Core_DAO $dao
  * @param array $params
  * @param bool $unique
- * @param string $entity
  *
  * @throws API_Exception
  * @throws Exception
  */
-function _civicrm_api3_dao_set_filter(&$dao, $params, $unique = TRUE, $entity) {
-  $entity = substr($dao->__table, 8);
-  if (!empty($params[$entity . "_id"]) && empty($params['id'])) {
+function _civicrm_api3_dao_set_filter(&$dao, $params, $unique = TRUE) {
+  $entity = _civicrm_api_get_entity_name_from_dao($dao);
+  $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity);
+  if (!empty($params[$lowercase_entity . "_id"]) && empty($params['id'])) {
     //if entity_id is set then treat it as ID (will be overridden by id if set)
-    $params['id'] = $params[$entity . "_id"];
+    $params['id'] = $params[$lowercase_entity . "_id"];
   }
   $allfields = _civicrm_api3_build_fields_array($dao, $unique);
   $fields = array_intersect(array_keys($allfields), array_keys($params));
@@ -633,21 +675,24 @@ function _civicrm_api3_dao_set_filter(&$dao, $params, $unique = TRUE, $entity) {
   }
   if (!empty($options['return']) && is_array($options['return']) && empty($options['is_count'])) {
     $dao->selectAdd();
-    $options['return']['id'] = TRUE;// ensure 'id' is included
+    // Ensure 'id' is included.
+    $options['return']['id'] = TRUE;
     $allfields = _civicrm_api3_get_unique_name_array($dao);
     $returnMatched = array_intersect(array_keys($options['return']), $allfields);
     foreach ($returnMatched as $returnValue) {
       $dao->selectAdd($returnValue);
     }
 
-    $unmatchedFields = array_diff(// not already matched on the field names
+    // Not already matched on the field names.
+    $unmatchedFields = array_diff(
       array_keys($options['return']),
       $returnMatched
     );
 
     $returnUniqueMatched = array_intersect(
       $unmatchedFields,
-      array_flip($allfields)// but a match for the field keys
+      // But a match for the field keys.
+      array_flip($allfields)
     );
     foreach ($returnUniqueMatched as $uniqueVal) {
       $dao->selectAdd($allfields[$uniqueVal]);
@@ -657,7 +702,8 @@ function _civicrm_api3_dao_set_filter(&$dao, $params, $unique = TRUE, $entity) {
 }
 
 /**
- * Apply filters (e.g. high, low) to DAO object (prior to find)
+ * Apply filters (e.g. high, low) to DAO object (prior to find).
+ *
  * @param string $filterField
  *   Field name of filter.
  * @param string $filterValue
@@ -686,12 +732,13 @@ function _civicrm_api3_apply_filters_to_dao($filterField, $filterValue, &$dao) {
 
 /**
  * Get sort, limit etc options from the params - supporting old & new formats.
- * get returnproperties for legacy
+ *
+ * Get returnProperties for legacy
  *
  * @param array $params
  *   Params array as passed into civicrm_api.
  * @param bool $queryObject
- *   Is this supporting a queryobject api (e.g contact) - if so we support more options.
+ *   Is this supporting a queryObject api (e.g contact) - if so we support more options.
  *   for legacy report & return a unique fields array
  *
  * @param string $entity
@@ -702,6 +749,7 @@ function _civicrm_api3_apply_filters_to_dao($filterField, $filterValue, &$dao) {
  *   options extracted from params
  */
 function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $entity = '', $action = '') {
+  $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity);
   $is_count = FALSE;
   $sort = CRM_Utils_Array::value('sort', $params, 0);
   $sort = CRM_Utils_Array::value('option.sort', $params, $sort);
@@ -737,14 +785,14 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $
   }
   if ($entity && $action == 'get') {
     if (!empty($returnProperties['id'])) {
-      $returnProperties[$entity . '_id'] = 1;
+      $returnProperties[$lowercase_entity . '_id'] = 1;
       unset($returnProperties['id']);
     }
     switch (trim(strtolower($sort))) {
       case 'id':
       case 'id desc':
       case 'id asc':
-        $sort = str_replace('id', $entity . '_id', $sort);
+        $sort = str_replace('id', $lowercase_entity . '_id', $sort);
     }
   }
 
@@ -775,7 +823,7 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $
       $legacyreturnProperties[substr($n, 7)] = $v;
     }
     elseif ($n == 'id') {
-      $inputParams[$entity . '_id'] = $v;
+      $inputParams[$lowercase_entity . '_id'] = $v;
     }
     elseif (in_array($n, $otherVars)) {
     }
@@ -792,7 +840,7 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $
 }
 
 /**
- * Apply options (e.g. sort, limit, order by) to DAO object (prior to find)
+ * Apply options (e.g. sort, limit, order by) to DAO object (prior to find).
  *
  * @param array $params
  *   Params array as passed into civicrm_api.
@@ -814,7 +862,9 @@ function _civicrm_api3_apply_options_to_dao(&$params, &$dao, $entity) {
 }
 
 /**
- * build fields array. This is the array of fields as it relates to the given DAO
+ * Build fields array.
+ *
+ * This is the array of fields as it relates to the given DAO
  * returns unique fields as keys by default but if set but can return by DB fields
  *
  * @param CRM_Core_DAO $bao
@@ -826,9 +876,9 @@ function _civicrm_api3_build_fields_array(&$bao, $unique = TRUE) {
   $fields = $bao->fields();
   if ($unique) {
     if (empty($fields['id'])) {
-      $entity = _civicrm_api_get_entity_name_from_dao($bao);
-      $fields['id'] = $fields[$entity . '_id'];
-      unset($fields[$entity . '_id']);
+      $lowercase_entity = _civicrm_api_get_entity_name_from_camel(_civicrm_api_get_entity_name_from_dao($bao));
+      $fields['id'] = $fields[$lowercase_entity . '_id'];
+      unset($fields[$lowercase_entity . '_id']);
     }
     return $fields;
   }
@@ -840,7 +890,9 @@ function _civicrm_api3_build_fields_array(&$bao, $unique = TRUE) {
 }
 
 /**
- * build fields array. This is the array of fields as it relates to the given DAO
+ * Build fields array.
+ *
+ * This is the array of fields as it relates to the given DAO
  * returns unique fields as keys by default but if set but can return by DB fields
  *
  * @param CRM_Core_DAO $bao
@@ -856,7 +908,7 @@ function _civicrm_api3_get_unique_name_array(&$bao) {
 }
 
 /**
- * Converts an DAO object to an array
+ * Converts an DAO object to an array.
  *
  * @param CRM_Core_DAO $dao
  *   Object to convert.
@@ -906,6 +958,8 @@ function _civicrm_api3_dao_to_array($dao, $params = NULL, $uniqueFields = TRUE,
 }
 
 /**
+ * Determine if custom fields need to be retrieved.
+ *
  * We currently retrieve all custom fields or none at this level so if we know the entity
  * && it can take custom fields & there is the string 'custom' in their return request we get them all, they are filtered on the way out
  * @todo filter so only required fields are queried
@@ -921,14 +975,14 @@ function _civicrm_api3_custom_fields_are_required($entity, $params) {
     return FALSE;
   }
   $options = _civicrm_api3_get_options_from_params($params);
-  //we check for possibility of 'custom' => 1 as well as specific custom fields
+  // We check for possibility of 'custom' => 1 as well as specific custom fields.
   $returnString = implode('', $options['return']) . implode('', array_keys($options['return']));
   if (stristr($returnString, 'custom')) {
     return TRUE;
   }
 }
 /**
- * Converts an object to an array
+ * Converts an object to an array.
  *
  * @param object $dao
  *   (reference) object to convert.
@@ -947,9 +1001,11 @@ function _civicrm_api3_object_to_array(&$dao, &$values, $uniqueFields = FALSE) {
 }
 
 /**
- * Wrapper for _civicrm_object_to_array when api supports unique fields
+ * Wrapper for _civicrm_object_to_array when api supports unique fields.
+ *
  * @param $dao
  * @param $values
+ *
  * @return array
  */
 function _civicrm_api3_object_to_array_unique_fields(&$dao, &$values) {
@@ -957,6 +1013,7 @@ function _civicrm_api3_object_to_array_unique_fields(&$dao, &$values) {
 }
 
 /**
+ * Format custom parameters.
  *
  * @param array $params
  * @param array $values
@@ -995,6 +1052,8 @@ function _civicrm_api3_custom_format_params($params, &$values, $extends, $entity
 }
 
 /**
+ * Format parameters for create action.
+ *
  * @param array $params
  * @param $entity
  */
@@ -1011,7 +1070,9 @@ function _civicrm_api3_format_params_for_create(&$params, $entity) {
 }
 
 /**
- * we can't rely on downstream to add separators to checkboxes so we'll check here. We should look at pushing to BAO function
+ * We can't rely on downstream to add separators to checkboxes so we'll check here.
+ *
+ * We should look at pushing to BAO function
  * and / or validate function but this is a safe place for now as it has massive test coverage & we can keep the change very specific
  * note that this is specifically tested in the GRANT api test case so later refactoring should use that as a checking point
  *
@@ -1029,20 +1090,19 @@ function _civicrm_api3_format_params_for_create(&$params, $entity) {
  * @todo - we are probably skipping handling disabled options as presumably getoptions is not giving us them. This should be non-regressive but might
  * be fixed in future
  *
- * @param $checkboxFieldValue
- * @param $customFieldLabel
- * @param $entity
- *
+ * @param mixed $checkboxFieldValue
+ * @param string $customFieldLabel
+ * @param string $entity
  */
 function formatCheckBoxField(&$checkboxFieldValue, $customFieldLabel, $entity) {
 
   if (is_string($checkboxFieldValue) && stristr($checkboxFieldValue, CRM_Core_DAO::VALUE_SEPARATOR)) {
-    // we can assume it's pre-formatted
+    // We can assume it's pre-formatted.
     return;
   }
   $options = civicrm_api($entity, 'getoptions', array('field' => $customFieldLabel, 'version' => 3));
   if (!empty($options['is_error'])) {
-    //the check is precautionary - can probably be removed later
+    // The check is precautionary - can probably be removed later.
     return;
   }
 
@@ -1106,25 +1166,26 @@ function formatCheckBoxField(&$checkboxFieldValue, $customFieldLabel, $entity) {
 }
 
 /**
+ * This function ensures that we have the right input parameters.
+ *
  * @deprecated
- * This function ensures that we have the right input parameters
  *
  * This function is only called when $dao is passed into verify_mandatory.
  * The practice of passing $dao into verify_mandatory turned out to be
- * unsatisfactory as the required fields @ the dao level is so diffent to the abstract
+ * unsatisfactory as the required fields @ the dao level is so different to the abstract
  * api level. Hence the intention is to remove this function
- * & the associated param from viery_mandatory
+ * & the associated param from verify_mandatory
  *
  * @param array $params
  *   Associative array of property name/value.
- *                             pairs to insert in new history.
+ *   pairs to insert in new history.
  * @param string $daoName
  * @param bool $return
  *
  * @daoName string DAO to check params agains
  *
  * @return bool
- *   Sshould the missing fields be returned as an array (core error created as default)
+ *   Should the missing fields be returned as an array (core error created as default)
  *   true if all fields present, depending on $result a core error is created of an array of missing fields is returned
  */
 function _civicrm_api3_check_required_fields($params, $daoName, $return = FALSE) {
@@ -1172,7 +1233,7 @@ function _civicrm_api3_check_required_fields($params, $daoName, $return = FALSE)
 }
 
 /**
- * Function to do a 'standard' api get - when the api is only doing a $bao->find then use this
+ * Function to do a 'standard' api get - when the api is only doing a $bao->find then use this.
  *
  * @param string $bao_name
  *   Name of BAO.
@@ -1186,7 +1247,7 @@ function _civicrm_api3_check_required_fields($params, $daoName, $return = FALSE)
  */
 function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $entity = "") {
   $bao = new $bao_name();
-  _civicrm_api3_dao_set_filter($bao, $params, TRUE, $entity);
+  _civicrm_api3_dao_set_filter($bao, $params, TRUE);
   if ($returnAsSuccess) {
     return civicrm_api3_create_success(_civicrm_api3_dao_to_array($bao, $params, FALSE, $entity), $params, $entity, 'get');
   }
@@ -1196,7 +1257,7 @@ function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $
 }
 
 /**
- * Function to do a 'standard' api create - when the api is only doing a $bao::create then use this
+ * Function to do a 'standard' api create - when the api is only doing a $bao::create then use this.
  *
  * @param string $bao_name
  *   Name of BAO Class.
@@ -1211,7 +1272,7 @@ function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $
 function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
   _civicrm_api3_format_params_for_create($params, $entity);
   $args = array(&$params);
-  if (!empty($entity)) {
+  if ($entity) {
     $ids = array($entity => CRM_Utils_Array::value('id', $params));
     $args[] = &$ids;
   }
@@ -1261,7 +1322,9 @@ function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
  * @param array $params
  *
  * @throws API_Exception
- * @return CRM_Core_DAO|NULL an instance of the BAO
+ *
+ * @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);
@@ -1286,8 +1349,9 @@ function _civicrm_api3_basic_create_fallback($bao_name, &$params) {
 }
 
 /**
- * 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
+ * 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.
  *
  * @param string $bao_name
  * @param array $params
@@ -1325,7 +1389,10 @@ function _civicrm_api3_basic_delete($bao_name, &$params) {
 }
 
 /**
- * Get custom data for the given entity & Add it to the returnArray as 'custom_123' = 'custom string' AND 'custom_123_1' = 'custom string'
+ * Get custom data for the given entity & Add it to the returnArray.
+ *
+ * This looks like 'custom_123' = 'custom string' AND
+ * 'custom_123_1' = 'custom string'
  * Where 123 is field value & 1 is the id within the custom group data table (value ID)
  *
  * @param array $returnArray
@@ -1374,11 +1441,14 @@ function _civicrm_api3_custom_data_get(&$returnArray, $entity, $entity_id, $grou
 }
 
 /**
- * Validate fields being passed into API. This function relies on the getFields function working accurately
+ * Validate fields being passed into API.
+ *
+ * This function relies on the getFields function working accurately
  * for the given API. If error mode is set to TRUE then it will also check
  * foreign keys
  *
  * As of writing only date was implemented.
+ *
  * @param string $entity
  * @param string $action
  * @param array $params
@@ -1387,10 +1457,24 @@ function _civicrm_api3_custom_data_get(&$returnArray, $entity, $entity_id, $grou
  *   Response from getfields all variables are the same as per civicrm_api.
  * @param bool $errorMode
  *   ErrorMode do intensive post fail checks?.
+ *
  * @throws Exception
  */
 function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $errorMode = FALSE) {
+  //CRM-15792 handle datetime for custom fields below code handles chain api call
+  $chainApikeys = array_flip(preg_grep("/^api./", array_keys($params)));
+  if (!empty($chainApikeys) && is_array($chainApikeys)) {
+    foreach ($chainApikeys as $key => $value) {
+      if (is_array($params[$key])) {
+        $chainApiParams = array_intersect_key($fields, $params[$key]);
+        $customFields = array_fill_keys(array_keys($params[$key]), $key);
+      }
+    }
+  }
   $fields = array_intersect_key($fields, $params);
+  if (!empty($chainApiParams)) {
+    $fields = array_merge($fields, $chainApiParams);
+  }
   foreach ($fields as $fieldName => $fieldInfo) {
     switch (CRM_Utils_Array::value('type', $fieldInfo)) {
       case CRM_Utils_Type::T_INT:
@@ -1398,11 +1482,17 @@ function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $err
         _civicrm_api3_validate_integer($params, $fieldName, $fieldInfo, $entity);
         break;
 
-      case 4:
-      case 12:
+      case CRM_Utils_Type::T_DATE:
+      case CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME:
       case CRM_Utils_Type::T_TIMESTAMP:
         //field is of type date or datetime
-        _civicrm_api3_validate_date($params, $fieldName, $fieldInfo);
+        if (!empty($customFields) && array_key_exists($fieldName, $customFields)) {
+          $dateParams = &$params[$customFields[$fieldName]];
+        }
+        else {
+          $dateParams = &$params;
+        }
+        _civicrm_api3_validate_date($dateParams, $fieldName, $fieldInfo);
         break;
 
       case 32:
@@ -1447,6 +1537,7 @@ function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $err
 
 /**
  * Validate date fields being passed into API.
+ *
  * It currently converts both unique fields and DB field names to a mysql date.
  * @todo - probably the unique field handling & the if exists handling is now done before this
  * function is reached in the wrapper - can reduce this code down to assume we
@@ -1461,6 +1552,7 @@ function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $err
  *   Uniquename of field being checked.
  * @param array $fieldInfo
  *   Array of fields from getfields function.
+ *
  * @throws Exception
  */
 function _civicrm_api3_validate_date(&$params, &$fieldName, &$fieldInfo) {
@@ -1485,8 +1577,9 @@ function _civicrm_api3_validate_date(&$params, &$fieldName, &$fieldInfo) {
 }
 
 /**
- * convert date into BAO friendly date
- * we accept 'whatever strtotime accepts'
+ * Convert date into BAO friendly date.
+ *
+ * We accept 'whatever strtotime accepts'
  *
  * @param string $dateValue
  * @param string $fieldName
@@ -1517,6 +1610,7 @@ function _civicrm_api3_getValidDate($dateValue, $fieldName, $fieldType) {
  *   Uniquename of field being checked.
  * @param array $fieldInfo
  *   Array of fields from getfields function.
+ *
  * @throws \API_Exception
  */
 function _civicrm_api3_validate_constraint(&$fieldValue, &$fieldName, &$fieldInfo) {
@@ -1537,6 +1631,7 @@ function _civicrm_api3_validate_constraint(&$fieldValue, &$fieldName, &$fieldInf
  *   Params from civicrm_api.
  * @param string $fieldName
  *   Uniquename of field being checked.
+ *
  * @throws Exception
  */
 function _civicrm_api3_validate_unique_key(&$params, &$fieldName) {
@@ -1561,7 +1656,7 @@ function _civicrm_api3_validate_unique_key(&$params, &$fieldName) {
  * Replace the old set of entities (matching some given keys) with a new set of
  * entities (matching the same keys).
  *
- * Note: This will verify that 'values' is present, but it does not directly verify
+ * @note This will verify that 'values' is present, but it does not directly verify
  * any other parameters.
  *
  * @param string $entity
@@ -1569,7 +1664,8 @@ function _civicrm_api3_validate_unique_key(&$params, &$fieldName) {
  * @param array $params
  *   Params from civicrm_api, including:.
  *   - 'values': an array of records to save
- *   - all other items: keys which identify new/pre-existing records
+ *   - all other items: keys which identify new/pre-existing records.
+ *
  * @return array|int
  */
 function _civicrm_api3_generic_replace($entity, $params) {
@@ -1635,9 +1731,11 @@ function _civicrm_api3_generic_replace($entity, $params) {
 }
 
 /**
+ * Replace base parameters.
+ *
  * @param array $params
  *
- * @return mixed
+ * @return array
  */
 function _civicrm_api3_generic_replace_base_params($params) {
   $baseParams = $params;
@@ -1648,7 +1746,7 @@ function _civicrm_api3_generic_replace_base_params($params) {
 }
 
 /**
- * returns fields allowable by api
+ * Returns fields allowable by api.
  *
  * @param $entity
  *   String Entity to query.
@@ -1659,7 +1757,13 @@ function _civicrm_api3_generic_replace_base_params($params) {
  * @return array
  */
 function _civicrm_api_get_fields($entity, $unique = FALSE, &$params = array()) {
-  $unsetIfEmpty = array('dataPattern', 'headerPattern', 'default', 'export', 'import');
+  $unsetIfEmpty = array(
+    'dataPattern',
+    'headerPattern',
+    'default',
+    'export',
+    'import',
+  );
   $dao = _civicrm_api3_get_DAO($entity);
   if (empty($dao)) {
     return array();
@@ -1702,10 +1806,13 @@ function _civicrm_api_get_fields($entity, $unique = FALSE, &$params = array()) {
 }
 
 /**
- * Return an array of fields for a given entity - this is the same as the BAO function but
- * fields are prefixed with 'custom_' to represent api params
+ * Return an array of fields for a given entity.
+ *
+ * This is the same as the BAO function but fields are prefixed with 'custom_' to represent api params.
+ *
  * @param $entity
  * @param array $params
+ *
  * @return array
  */
 function _civicrm_api_get_custom_fields($entity, &$params) {
@@ -1731,18 +1838,25 @@ function _civicrm_api_get_custom_fields($entity, &$params) {
     // Regular fields have a 'name' property
     $value['name'] = 'custom_' . $key;
     $value['title'] = $value['label'];
-    $value['type'] = _getStandardTypeFromCustomDataType($value['data_type']);
+    $value['type'] = _getStandardTypeFromCustomDataType($value);
     $ret['custom_' . $key] = $value;
   }
   return $ret;
 }
 
 /**
- * Translate the custom field data_type attribute into a std 'type'
+ * Translate the custom field data_type attribute into a std 'type'.
+ *
  * @param $dataType
+ *
  * @return int
  */
-function _getStandardTypeFromCustomDataType($dataType) {
+function _getStandardTypeFromCustomDataType($value) {
+  $dataType = $value['data_type'];
+  //CRM-15792 - If date custom field contains timeformat change type to DateTime
+  if ($value['data_type'] == 'Date' && isset($value['time_format']) && $value['time_format'] > 0) {
+    $dataType = 'DateTime';
+  }
   $mapping = array(
     'String' => CRM_Utils_Type::T_STRING,
     'Int' => CRM_Utils_Type::T_INT,
@@ -1750,6 +1864,7 @@ function _getStandardTypeFromCustomDataType($dataType) {
     'Memo' => CRM_Utils_Type::T_LONGTEXT,
     'Float' => CRM_Utils_Type::T_FLOAT,
     'Date' => CRM_Utils_Type::T_DATE,
+    'DateTime' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
     'Boolean' => CRM_Utils_Type::T_BOOLEAN,
     'StateProvince' => CRM_Utils_Type::T_INT,
     'File' => CRM_Utils_Type::T_STRING,
@@ -1762,10 +1877,12 @@ function _getStandardTypeFromCustomDataType($dataType) {
 
 
 /**
- * Fill params array with alternate (alias) values where a field has an alias and that is filled & the main field isn't
+ * Fill params array with alternate (alias) values where a field has an alias and that is filled & the main field isn't.
+ *
  * If multiple aliases the last takes precedence
  *
  * Function also swaps unique fields for non-unique fields & vice versa.
+ *
  * @param $apiRequest
  * @param $fields
  */
@@ -1805,7 +1922,8 @@ function _civicrm_api3_swap_out_aliases(&$apiRequest, $fields) {
 
 /**
  * Validate integer fields being passed into API.
- * It currently converts the incoming value 'user_contact_id' into the id of the currently logged in user
+ *
+ * It currently converts the incoming value 'user_contact_id' into the id of the currently logged in user.
  *
  * @param array $params
  *   Params from civicrm_api.
@@ -1814,6 +1932,7 @@ function _civicrm_api3_swap_out_aliases(&$apiRequest, $fields) {
  * @param array $fieldInfo
  *   Array of fields from getfields function.
  * @param string $entity
+ *
  * @throws API_Exception
  */
 function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $entity) {
@@ -1847,7 +1966,7 @@ function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $ent
     // Check our field length
     if (is_string($fieldValue) && !empty($fieldInfo['maxlength']) && strlen($fieldValue) > $fieldInfo['maxlength']
       ) {
-      throw new API_Exception( $fieldValue . " is " . strlen($fieldValue) . " characters  - longer than $fieldName length" . $fieldInfo['maxlength'] . ' characters',
+      throw new API_Exception($fieldValue . " is " . strlen($fieldValue) . " characters  - longer than $fieldName length" . $fieldInfo['maxlength'] . ' characters',
         2100, array('field' => $fieldName, "max_length" => $fieldInfo['maxlength'])
       );
     }
@@ -1862,14 +1981,15 @@ function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $ent
 }
 
 /**
- * Determine a contact ID using a string expression
+ * Determine a contact ID using a string expression.
  *
  * @param string $contactIdExpr
  *   E.g. "user_contact_id" or "@user:username".
+ *
  * @return int|NULL|'unknown-user'
  */
 function _civicrm_api3_resolve_contactID($contactIdExpr) {
-  //if value = 'user_contact_id' replace value with logged in user id
+  // If value = 'user_contact_id' replace value with logged in user id.
   if ($contactIdExpr == "user_contact_id") {
     return CRM_Core_Session::getLoggedInContactID();
   }
@@ -1892,7 +2012,8 @@ function _civicrm_api3_resolve_contactID($contactIdExpr) {
 }
 
 /**
- * Validate html (check for scripting attack)
+ * Validate html (check for scripting attack).
+ *
  * @param array $params
  * @param string $fieldName
  * @param array $fieldInfo
@@ -1913,6 +2034,7 @@ function _civicrm_api3_validate_html(&$params, &$fieldName, $fieldInfo) {
 
 /**
  * Validate string fields being passed into API.
+ *
  * @param array $params
  *   Params from civicrm_api.
  * @param string $fieldName
@@ -1920,6 +2042,7 @@ function _civicrm_api3_validate_html(&$params, &$fieldName, $fieldInfo) {
  * @param array $fieldInfo
  *   Array of fields from getfields function.
  * @param string $entity
+ *
  * @throws API_Exception
  * @throws Exception
  */
@@ -1969,12 +2092,13 @@ function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $enti
 }
 
 /**
- * Validate & swap out any pseudoconstants / options
+ * Validate & swap out any pseudoconstants / options.
  *
  * @param mixed $fieldValue
  * @param string $entity : api entity name
  * @param string $fieldName : field name used in api call (not necessarily the canonical name)
  * @param array $fieldInfo : getfields meta-data
+ *
  * @throws \API_Exception
  */
 function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldName, $fieldInfo) {
@@ -1982,20 +2106,24 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
 
   if (!$options) {
     if (strtolower($entity) == 'profile' && !empty($fieldInfo['entity'])) {
-      // we need to get the options from the entity the field relates to
+      // We need to get the options from the entity the field relates to.
       $entity = $fieldInfo['entity'];
     }
-    $options = civicrm_api($entity, 'getoptions', array('version' => 3, 'field' => $fieldInfo['name'], 'context' => 'validate'));
+    $options = civicrm_api($entity, 'getoptions', array(
+      'version' => 3,
+      'field' => $fieldInfo['name'],
+      'context' => 'validate',
+    ));
     $options = CRM_Utils_Array::value('values', $options, array());
   }
 
-  // If passed a value-separated string, explode to an array, then re-implode after matching values
+  // If passed a value-separated string, explode to an array, then re-implode after matching values.
   $implode = FALSE;
   if (is_string($fieldValue) && strpos($fieldValue, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) {
     $fieldValue = CRM_Utils_Array::explodePadded($fieldValue);
     $implode = TRUE;
   }
-  // If passed multiple options, validate each
+  // If passed multiple options, validate each.
   if (is_array($fieldValue)) {
     foreach ($fieldValue as &$value) {
       if (!is_array($value)) {
@@ -2015,11 +2143,12 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
 }
 
 /**
- * Validate & swap a single option value for a field
+ * Validate & swap a single option value for a field.
  *
  * @param string $value field value
  * @param array $options array of options for this field
  * @param string $fieldName field name used in api call (not necessarily the canonical name)
+ *
  * @throws API_Exception
  */
 function _civicrm_api3_api_match_pseudoconstant_value(&$value, $options, $fieldName) {
@@ -2046,7 +2175,7 @@ function _civicrm_api3_api_match_pseudoconstant_value(&$value, $options, $fieldN
 }
 
 /**
- * Returns the canonical name of a field
+ * Returns the canonical name of a field.
  *
  * @param $entity
  *   api entity name (string should already be standardized - no camelCase).
@@ -2086,18 +2215,21 @@ function _civicrm_api3_api_resolve_alias($entity, $fieldName) {
 }
 
 /**
+ * Check if the function is deprecated.
+ *
  * @param string $entity
  * @param array $result
+ *
  * @return string|array|null
  */
 function _civicrm_api3_deprecation_check($entity, $result = array()) {
   if ($entity) {
-    $apiFile = 'api/v3/' . _civicrm_api_get_camel_name($entity) . '.php';
+    $apiFile = "api/v3/$entity.php";
     if (CRM_Utils_File::isIncludable($apiFile)) {
       require_once $apiFile;
     }
-    $entity = _civicrm_api_get_entity_name_from_camel($entity);
-    $fnName = "_civicrm_api3_{$entity}_deprecation";
+    $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity);
+    $fnName = "_civicrm_api3_{$lowercase_entity}_deprecation";
     if (function_exists($fnName)) {
       return $fnName($result);
     }
@@ -2105,11 +2237,14 @@ function _civicrm_api3_deprecation_check($entity, $result = array()) {
 }
 
 /**
+ * Get the actual field value.
+ *
  * In some case $params[$fieldName] holds Array value in this format Array([operator] => [value])
  * So this function returns the actual field value
  *
  * @param array $params
  * @param string $fieldName
+ *
  * @return mixed
  */
 function _civicrm_api3_field_value_check(&$params, $fieldName) {