Merge pull request #4923 from colemanw/invoice_id
[civicrm-core.git] / api / v3 / utils.php
index 6942074631c848ede83bd2fb9bd7d9b661442455..7deeab9744d0c79df0e7ec8631c60651ffc7b110 100644 (file)
@@ -56,7 +56,7 @@ function _civicrm_api3_initialize() {
  *   List of required fields options. One of the options is required.
  *
  * @return null
  *   or throws error if there the required fields not present
+ *   or throws error if there the required fields not present
  * @
  */
 function civicrm_api3_verify_one_mandatory($params, $daoName = NULL, $keyoptions = array()) {
@@ -80,7 +80,7 @@ function civicrm_api3_verify_one_mandatory($params, $daoName = NULL, $keyoptions
  *
  * @throws API_Exception
  * @return null
  *   or throws error if there the required fields not present
+ *   or throws error if there the required fields not present
  *
  * @todo see notes on _civicrm_api3_check_required_fields regarding removing $daoName param
  */
@@ -135,11 +135,9 @@ function civicrm_api3_verify_mandatory($params, $daoName = NULL, $keys = array()
 
 /**
  *
+ * @param $msg
  * @param array $data
- *
- * @throws API_Exception
  * @return array
-   *   <type>
  */
 function civicrm_api3_create_error($msg, $data = array()) {
   $data['is_error'] = 1;
@@ -272,6 +270,8 @@ function civicrm_api3_create_success($values = 1, $params = array(), $entity = N
 
 /**
  * Load the DAO of the entity
+ * @param $entity
+ * @return bool
  */
 function _civicrm_api3_load_DAO($entity) {
   $dao = _civicrm_api3_get_DAO($entity);
@@ -286,8 +286,8 @@ function _civicrm_api3_load_DAO($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 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) {
@@ -354,8 +354,8 @@ function _civicrm_api3_get_DAO($name) {
  * 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 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) {
@@ -375,7 +375,7 @@ function _civicrm_api3_get_BAO($name) {
 
 /**
  *  Recursive function to explode value-separated strings into arrays
- *
+ * @param $values
  */
 function _civicrm_api3_separate_values(&$values) {
   $sp = CRM_Core_DAO::VALUE_SEPARATOR;
@@ -384,7 +384,7 @@ 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
+      if ($key == 'case_type_id') {// this is to honor the way case API was originally written
         $value = trim(str_replace($sp, ',', $value), ',');
       }
       elseif (strpos($value, $sp) !== FALSE) {
@@ -439,7 +439,7 @@ function _civicrm_api3_store_values(&$fields, &$params, &$values) {
  *  others that use the query object. Note that this function passes permission information in.
  *  The others don't
  *
- * Ideally this would be merged with _civicrm_get_query_object but we need to resolve differences in what the
+ * 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
@@ -542,7 +542,7 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti
  * @param array $params
  * @param string $mode
  * @param string $entity
- * @return CRM_Core_DAO query object
+ * @return array(CRM_Core_DAO|CRM_Contact_BAO_Query)
  */
 function _civicrm_api3_get_query_object($params, $mode, $entity) {
   $options          = _civicrm_api3_get_options_from_params($params, TRUE, $entity, 'get');
@@ -700,14 +700,14 @@ function _civicrm_api3_apply_filters_to_dao($filterField, $filterValue, &$dao) {
  *   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.
- * for legacy report & return a unique fields array
+ *   for legacy report & return a unique fields array
  *
  * @param string $entity
  * @param string $action
  *
  * @throws API_Exception
  * @return array
  *   options extracted from params
+ *   options extracted from params
  */
 function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $entity = '', $action = '') {
   $is_count = FALSE;
@@ -824,6 +824,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
  * returns unique fields as keys by default but if set but can return by DB fields
+ * @param $bao
+ * @param bool $unique
+ * @return
  */
 function _civicrm_api3_build_fields_array(&$bao, $unique = TRUE) {
   $fields = $bao->fields();
@@ -845,7 +848,7 @@ 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
  * returns unique fields as keys by default but if set but can return by DB fields
- * @param CRM_Core_BAO $bao
+ * @param CRM_Core_DAO $bao
  *
  * @return mixed
  */
@@ -869,8 +872,6 @@ function _civicrm_api3_get_unique_name_array(&$bao) {
  *
  * @return array
  *
- * @static void
- * @access public
  */
 function _civicrm_api3_dao_to_array($dao, $params = NULL, $uniqueFields = TRUE, $entity = "", $autoFind = TRUE) {
   $result = array();
@@ -942,8 +943,6 @@ function _civicrm_api3_custom_fields_are_required($entity, $params) {
  * @param array|bool $uniqueFields
  *
  * @return array
- * @static void
- * @access public
  */
 function _civicrm_api3_object_to_array(&$dao, &$values, $uniqueFields = FALSE) {
 
@@ -957,6 +956,9 @@ function _civicrm_api3_object_to_array(&$dao, &$values, $uniqueFields = FALSE) {
 
 /**
  * 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) {
   return _civicrm_api3_object_to_array($dao, $values, TRUE);
@@ -1132,7 +1134,6 @@ function formatCheckBoxField(&$checkboxFieldValue, $customFieldLabel, $entity) {
  * @return bool
  *   Sshould 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
- * @access public
  */
 function _civicrm_api3_check_required_fields($params, $daoName, $return = FALSE) {
   //@deprecated - see notes
@@ -1300,7 +1301,7 @@ function _civicrm_api3_basic_create_fallback($bao_name, &$params) {
  * @param array $params
  *
  * @return array
  *   API result array
+ *   API result array
  * @throws API_Exception
  */
 function _civicrm_api3_basic_delete($bao_name, &$params) {
@@ -1425,9 +1426,12 @@ function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $err
         if (strpos($op, 'NULL') !== FALSE || strpos($op, 'EMPTY') !== FALSE) {
           break;
         }
-        if (!CRM_Utils_Rule::money($fieldValue) && !empty($fieldValue)) {
-          throw new Exception($fieldName . " is  not a valid amount: " . $params[$fieldName]);
+        foreach((array)$fieldValue as $fieldvalue) {
+          if (!CRM_Utils_Rule::money($fieldvalue) && !empty($fieldvalue)) {
+            throw new Exception($fieldName . " is  not a valid amount: " . $params[$fieldName]);
+          }
         }
+        break;
     }
 
     // intensive checks - usually only called after DB level fail
@@ -1442,7 +1446,7 @@ function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $err
       }
       if (!empty($fieldInfo['api.unique'])) {
         $params['entity'] = $entity;
-        _civicrm_api3_validate_uniquekey($params, $fieldName, $fieldInfo);
+        _civicrm_api3_validate_unique_key($params, $fieldName);
       }
     }
   }
@@ -1515,13 +1519,12 @@ function _civicrm_api3_getValidDate($dateValue, $fieldName, $fieldType) {
 /**
  * Validate foreign constraint fields being passed into API.
  *
- * @param array $params
- *   Params from civicrm_api.
+ * @param mixed $fieldValue
  * @param string $fieldName
  *   Uniquename of field being checked.
  * @param array $fieldInfo
  *   Array of fields from getfields function.
- * @throws Exception
+ * @throws \API_Exception
  */
 function _civicrm_api3_validate_constraint(&$fieldValue, &$fieldName, &$fieldInfo) {
   $dao = new $fieldInfo['FKClassName'];
@@ -1529,7 +1532,7 @@ function _civicrm_api3_validate_constraint(&$fieldValue, &$fieldName, &$fieldInf
   $dao->selectAdd();
   $dao->selectAdd('id');
   if (!$dao->find()) {
-    throw new Exception("$fieldName is not valid : " . $fieldValue);
+    throw new API_Exception("$fieldName is not valid : " . $fieldValue);
   }
 }
 
@@ -1540,11 +1543,9 @@ function _civicrm_api3_validate_constraint(&$fieldValue, &$fieldName, &$fieldInf
  *   Params from civicrm_api.
  * @param string $fieldName
  *   Uniquename of field being checked.
- * @param $fieldInfo
- *   Array of fields from getfields function.
  * @throws Exception
  */
-function _civicrm_api3_validate_uniquekey(&$params, &$fieldName, &$fieldInfo) {
+function _civicrm_api3_validate_unique_key(&$params, &$fieldName) {
   list($fieldValue, $op) = _civicrm_api3_field_value_check($params, $fieldName);
   if (strpos($op, 'NULL') !== FALSE || strpos($op, 'EMPTY') !== FALSE) {
     return;
@@ -1709,6 +1710,9 @@ 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
+ * @param $entity
+ * @param array $params
+ * @return array
  */
 function _civicrm_api_get_custom_fields($entity, &$params) {
   $entity = _civicrm_api_get_camel_name($entity);
@@ -1738,8 +1742,11 @@ function _civicrm_api_get_custom_fields($entity, &$params) {
   }
   return $ret;
 }
+
 /**
  * Translate the custom field data_type attribute into a std 'type'
+ * @param $dataType
+ * @return
  */
 function _getStandardTypeFromCustomDataType($dataType) {
   $mapping = array(
@@ -1765,6 +1772,8 @@ function _getStandardTypeFromCustomDataType($dataType) {
  * If multiple aliases the last takes precedence
  *
  * Function also swaps unique fields for non-unique fields & vice versa.
+ * @param $apiRequest
+ * @param $fields
  */
 function _civicrm_api3_swap_out_aliases(&$apiRequest, $fields) {
   foreach ($fields as $field => $values) {
@@ -1827,7 +1836,7 @@ function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $ent
       if ('unknown-user' === $realContactId) {
         throw new API_Exception("\"$fieldName\" \"{$fieldValue}\" cannot be resolved to a contact ID", 2002, array('error_field' => $fieldName,"type"=>"integer"));
       } elseif (is_numeric($realContactId)) {
-        $params[$fieldName]  = $fieldValue = $realContactId;
+        $fieldValue = $realContactId;
       }
     }
     if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) {
@@ -1843,12 +1852,19 @@ 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',
         2100, array('field' => $fieldName, "max_length"=>$fieldInfo['maxlength'])
       );
     }
   }
+
+  if (!empty($op)) {
+    $params[$fieldName][$op] = $fieldValue;
+  }
+  else {
+    $params[$fieldName] = $fieldValue;
+  }
 }
 
 /**
@@ -1915,12 +1931,11 @@ function _civicrm_api3_validate_html(&$params, &$fieldName, $fieldInfo) {
  */
 function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $entity) {
   list($fieldValue, $op) = _civicrm_api3_field_value_check($params, $fieldName);
-  if (strpos($op, 'NULL') !== FALSE || strpos($op, 'EMPTY') !== FALSE) {
+  if (strpos($op, 'NULL') !== FALSE || strpos($op, 'EMPTY') !== FALSE || CRM_Utils_System::isNull($fieldValue)) {
     return;
   }
-  // If fieldname exists in params
-  $fieldValue = !empty($fieldValue) ? $fieldValue : '';
-  if(!is_array($fieldValue)){
+
+  if (!is_array($fieldValue)) {
     $fieldValue = (string) $fieldValue;
   }
   else {
@@ -1929,47 +1944,47 @@ function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $enti
     // & many save incorrectly. But can we change them wholesale?
   }
   if ($fieldValue) {
-    if (!CRM_Utils_Rule::xssString($fieldValue)) {
-      throw new Exception('Illegal characters in input (potential scripting attack)');
-    }
-    if ($fieldName == 'currency') {
-      //When using IN operator $fieldValue is a array of currency codes
-      if (is_array($fieldValue)) {
-        foreach ($fieldValue as $currency) {
-          if (!CRM_Utils_Rule::currencyCode($currency)) {
-            throw new Exception("Currency not a valid code: $currency");
-          }
-        }
+    foreach ((array) $fieldValue as $value) {
+      if (!CRM_Utils_Rule::xssString($fieldValue)) {
+        throw new Exception('Illegal characters in input (potential scripting attack)');
       }
-      else {
-        if (!CRM_Utils_Rule::currencyCode($fieldValue)) {
-          throw new Exception("Currency not a valid code: $fieldValue");
+      if ($fieldName == 'currency') {
+        //When using IN operator $fieldValue is a array of currency codes
+        if (!CRM_Utils_Rule::currencyCode($value)) {
+          throw new Exception("Currency not a valid code: $currency");
         }
       }
     }
-    if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) {
-      _civicrm_api3_api_match_pseudoconstant($fieldValue, $entity, $fieldName, $fieldInfo);
-    }
-    // Check our field length
-    elseif (is_string($fieldValue) && !empty($fieldInfo['maxlength']) && strlen(utf8_decode($fieldValue)) > $fieldInfo['maxlength']) {
-      throw new API_Exception("Value for $fieldName is " . strlen(utf8_decode($value)) . " characters  - This field has a maxlength of {$fieldInfo['maxlength']} characters.",
-        2100, array('field' => $fieldName)
-      );
-    }
+  }
+  if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) {
+    _civicrm_api3_api_match_pseudoconstant($fieldValue, $entity, $fieldName, $fieldInfo);
+  }
+  // Check our field length
+  elseif (is_string($fieldValue) && !empty($fieldInfo['maxlength']) && strlen(utf8_decode($fieldValue)) > $fieldInfo['maxlength']) {
+    throw new API_Exception("Value for $fieldName is " . strlen(utf8_decode($value)) . " characters  - This field has a maxlength of {$fieldInfo['maxlength']} characters.",
+      2100, array('field' => $fieldName)
+    );
+  }
+
+  if (!empty($op)) {
+    $params[$fieldName][$op] = $fieldValue;
+  }
+  else {
+    $params[$fieldName] = $fieldValue;
   }
 }
 
 /**
  * Validate & swap out any pseudoconstants / options
  *
- * @param array $params: api parameters
- * @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
+ * @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) {
   $options = CRM_Utils_Array::value('options', $fieldInfo);
-  $pseudoconstant = CRM_Utils_Array::value('pseudoconstant', $fieldInfo);
 
   if (!$options) {
     if (strtolower($entity) == 'profile' && !empty($fieldInfo['entity'])) {
@@ -1978,12 +1993,6 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
     }
     $options = civicrm_api($entity, 'getoptions', array('version' => 3, 'field' => $fieldInfo['name'], 'context' => 'validate'));
     $options = CRM_Utils_Array::value('values', $options, array());
-
-    if (count($options) == 0 && isset($pseudoconstant['table'])) {
-        $pseudoParams = $pseudoconstant;
-        unset($pseudoParams['table']);
-        $options = CRM_Core_PseudoConstant::get(CRM_Core_DAO_AllCoreTables::getClassForTable($pseudoconstant['table']), $fieldName, $pseudoParams);
-    }
   }
 
   // If passed a value-separated string, explode to an array, then re-implode after matching values
@@ -2046,11 +2055,12 @@ function _civicrm_api3_api_match_pseudoconstant_value(&$value, $options, $fieldN
  * Returns the canonical name of a field
  *
  * @param $entity
- *   api entity name (string should already be standardized - no camelCase).
+ *   api entity name (string should already be standardized - no camelCase).
  * @param $fieldName
- *   any variation of a field's name (name, unique_name, api.alias).
+ *   any variation of a field's name (name, unique_name, api.alias).
  *
- * @return bool|string (string|bool) fieldName or FALSE if the field does not exist
+ * @return bool|string
+ *   fieldName or FALSE if the field does not exist
  */
 function _civicrm_api3_api_resolve_alias($entity, $fieldName) {
   if (strpos($fieldName, 'custom_') === 0 && is_numeric($fieldName[7])) {
@@ -2112,7 +2122,7 @@ function _civicrm_api3_field_value_check(&$params, $fieldName) {
   $fieldValue = CRM_Utils_Array::value($fieldName, $params);
   $op = NULL;
 
-  if (!empty($fieldValue) && is_array($fieldValue) && in_array(key($fieldValue), CRM_Core_DAO::acceptedSQLOperators())) {
+  if (!empty($fieldValue) && is_array($fieldValue) && array_search(key($fieldValue), CRM_Core_DAO::acceptedSQLOperators())) {
     $op = key($fieldValue);
     $fieldValue = CRM_Utils_Array::value($op, $fieldValue);
   }