<?php
/*
+--------------------------------------------------------------------+
- | CiviCRM version 4.3 |
+ | CiviCRM version 4.4 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2013 |
+--------------------------------------------------------------------+
*
* @param array $params array of fields to check
* @param array $daoName string DAO to check for required fields (create functions only)
- * @param array $keys list of required fields options. One of the options is required
+ * @param array $keyoptions
+ *
+ * @internal param array $keys list of required fields options. One of the options is required
* @return null or throws error if there the required fields not present
-
* @
- *
*/
function civicrm_api3_verify_one_mandatory($params, $daoName = NULL, $keyoptions = array(
)) {
* @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
* @return null or throws error if there the required fields not present
*
* @todo see notes on _civicrm_api3_check_required_fields regarding removing $daoName param
/**
*
- * @param <type> $msg
* @param <type> $data
+ * @param array $data
* @param object $dao DAO / BAO object to be freed here
*
- * @return <type>
+ * @throws API_Exception
+ * @return array <type>
*/
function civicrm_api3_create_error($msg, $data = array(), &$dao = NULL) {
//fix me - $dao should be param 4 & 3 should be $apiRequest
if (is_array($dao)) {
if ($msg == 'DB Error: constraint violation' || substr($msg, 0,9) == 'DB Error:' || $msg == 'DB Error: already exists') {
try {
- _civicrm_api3_validate_fields($dao['entity'], $dao['action'], $dao['params'], TRUE);
+ $fields = _civicrm_api3_api_getfields($dao);
+ _civicrm_api3_validate_fields($dao['entity'], $dao['action'], $dao['params'], $fields, TRUE);
}
catch(Exception $e) {
$msg = $e->getMessage();
$values[$key]['id'] = $item[$entity . "_id"];
}
if(!empty($item['financial_type_id'])){
+ //4.3 legacy handling
$values[$key]['contribution_type_id'] = $item['financial_type_id'];
}
+ if(!empty($item['next_sched_contribution_date'])){
+ // 4.4 legacy handling
+ $values[$key]['next_sched_contribution'] = $item['next_sched_contribution_date'];
+ }
}
}
/**
* Function to return the DAO of the function or Entity
- * @param $name is either a function of the api (civicrm_{entity}_create or the entity name
+ * @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) {
if (strpos($name, 'civicrm_api3') !== FALSE) {
/**
* Function to return the DAO of the function or Entity
- * @param $name is either a function of the api (civicrm_{entity}_create or the entity name
+ * @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) {
$dao = _civicrm_api3_get_DAO($name);
}
return $valueFound;
}
+
/**
* The API supports 2 types of get requestion. The more complex uses the BAO query object.
* This is a generic function for those functions that call it
* others that use the query object. Note that this function passes permission information in.
* The others don't
*
+ * @param $entity
* @param array $params as passed into api get or getcount function
- * @param array $options array of options (so we can modify the filter)
+ * @param array $additional_options
* @param bool $getCount are we just after the count
+ *
+ * @return
+ * @internal param array $options array of options (so we can modify the filter)
*/
function _civicrm_api3_get_using_query_object($entity, $params, $additional_options = array(), $getCount = NULL){
}
$newParams = CRM_Contact_BAO_Query::convertFormValues($inputParams);
+ foreach ($newParams as &$newParam) {
+ if($newParam[1] == '=' && is_array($newParam[2])) {
+ // we may be looking at an attempt to use the 'IN' style syntax
+ // @todo at time of writing only 'IN' & 'NOT IN' are supported for the array style syntax
+ $sqlFilter = CRM_Core_DAO::createSqlFilter($newParam[0], $params[$newParam[0]], 'String', NULL, TRUE);
+ if($sqlFilter) {
+ $newParam[1] = key($newParam[2]);
+ $newParam[2] = $sqlFilter;
+ }
+ }
+
+ }
$skipPermissions = CRM_Utils_Array::value('check_permissions', $params)? 0 :1;
+
list($entities, $options) = CRM_Contact_BAO_Query::apiQuery(
$newParams,
$returnProperties,
if (is_array($params[$field])) {
//get the actual fieldname from db
$fieldName = $allfields[$field]['name'];
- //array is the syntax for SQL clause
- foreach ($params[$field] as $operator => $criteria) {
- if (in_array($operator, $acceptedSQLOperators)) {
- switch ($operator) {
- // unary operators
-
- case 'IS NULL':
- case 'IS NOT NULL':
- $dao->whereAdd(sprintf('%s %s', $fieldName, $operator));
- break;
-
- // ternary operators
-
- case 'BETWEEN':
- case 'NOT BETWEEN':
- if (empty($criteria[0]) || empty($criteria[1])) {
- throw new exception("invalid criteria for $operator");
- }
- $dao->whereAdd(sprintf('%s ' . $operator . ' "%s" AND "%s"', $fieldName, CRM_Core_DAO::escapeString($criteria[0]), CRM_Core_DAO::escapeString($criteria[1])));
- break;
-
- // n-ary operators
-
- case 'IN':
- case 'NOT IN':
- if (empty($criteria)) {
- throw new exception("invalid criteria for $operator");
- }
- $escapedCriteria = array_map(array('CRM_Core_DAO', 'escapeString'), $criteria);
- $dao->whereAdd(sprintf('%s %s ("%s")', $fieldName, $operator, implode('", "', $escapedCriteria)));
- break;
-
- // binary operators
-
- default:
-
- $dao->whereAdd(sprintf('%s %s "%s"', $fieldName, $operator, CRM_Core_DAO::escapeString($criteria)));
- }
- }
+ $where = CRM_Core_DAO::createSqlFilter($fieldName, $params[$field], 'String');
+ if(!empty($where)) {
+ $dao->whereAdd($where);
}
}
else {
/**
* Get sort, limit etc options from the params - supporting old & new formats.
* 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
* for legacy report & return a unique fields array
+ *
+ * @param string $entity
+ * @param string $action
+ *
* @return array $options options extracted from params
*/
function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $entity = '', $action = '') {
/**
* Apply options (e.g. sort, limit, order by) to DAO object (prior to find)
+ *
* @param array $params params array as passed into civicrm_api
* @param object $dao DAO object
+ * @param $entity
*/
function _civicrm_api3_apply_options_to_dao(&$params, &$dao, $entity) {
/**
* Converts an DAO object to an array
*
- * @param object $dao (reference )object to convert
+ * @param object $dao (reference )object to convert
+ * @param null $params
+ * @param bool $uniqueFields
+ * @param string $entity
+ *
+ * @return array
+ *
* @params array of arrays (key = id) of array of fields
+ *
* @static void
* @access public
*/
/**
* Converts an object to an array
*
- * @param object $dao (reference) object to convert
- * @param array $values (reference) array
- * @param array $uniqueFields
+ * @param object $dao (reference) object to convert
+ * @param array $values (reference) array
+ * @param array|bool $uniqueFields
*
* @return array
* @static void
* api level. Hence the intention is to remove this function
* & the associated param from viery_mandatory
*
- * @param array $params Associative array of property name/value
+ * @param array $params Associative array of property name/value
* pairs to insert in new history.
+ * @param $daoName
+ * @param bool $return
+ *
* @daoName string DAO to check params agains
*
* @return bool should the missing fields be returned as an array (core error created as default)
* @param $params array params of the API call
* @param $throw bool whether to throw exception instead of returning false
*
+ * @throws Exception
* @return bool whether the current API user has the permission to make the call
*/
function _civicrm_api3_api_check_permission($entity, $action, &$params, $throw = TRUE) {
* @param string $bao_name name of BAO
* @param array $params params from api
* @param bool $returnAsSuccess return in api success format
+ * @param string $entity
+ *
+ * @return array
*/
function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $entity = "") {
$bao = new $bao_name();
* @param string $bao_name Name of BAO Class
* @param array $params parameters passed into the api call
* @param string $entity Entity - pass in if entity is non-standard & required $ids array
+ * @return array
*/
function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
else {
$values = array();
_civicrm_api3_object_to_array($bao, $values[$bao->id]);
- return civicrm_api3_create_success($values, $params, NULL, 'create', $bao);
+ return civicrm_api3_create_success($values, $params, $entity, 'create', $bao);
}
}
/**
* 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
+ * @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
+ *
+ * @throws API_Exception
* @return CRM_Core_DAO|NULL an instance of the BAO
*/
function _civicrm_api3_basic_create_fallback($bao_name, &$params) {
if ($bao !== FALSE) {
return civicrm_api3_create_success(TRUE);
}
- return civicrm_api3_create_error('Could not delete entity id ' . $params['id']);
+ throw new API_Exception('Could not delete entity id ' . $params['id']);
}
elseif (method_exists($bao_name, 'delete')) {
$dao = new $bao_name();
}
}
else {
- return civicrm_api3_create_error('Could not delete entity id ' . $params['id']);
+ throw new API_Exception('Could not delete entity id ' . $params['id']);
}
}
- return civicrm_api3_create_error('no delete method found');
+ throw new API_Exception('no delete method found');
}
/**
*
* @param array $returnArray - array to append custom data too - generally $result[4] where 4 is the entity id.
* @param string $entity e.g membership, event
+ * @param $entity_id
* @param int $groupID - per CRM_Core_BAO_CustomGroup::getTree
* @param int $subType e.g. membership_type_id where custom data doesn't apply to all membership types
* @param string $subName - Subtype of entity
- *
*/
function _civicrm_api3_custom_data_get(&$returnArray, $entity, $entity_id, $groupID = NULL, $subType = NULL, $subName = NULL) {
$groupTree = &CRM_Core_BAO_CustomGroup::getTree($entity,
* @param string $entity
* @param string $action
* @param array $params -
- * all variables are the same as per civicrm_api
+ * @param array $fields 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, $errorMode = NULL) {
- //skip any entities without working getfields functions
- $skippedEntities = array('entity', 'mailinggroup', 'customvalue', 'custom_value', 'mailing_group');
- if (in_array(strtolower($entity), $skippedEntities) || strtolower($action) == 'getfields') {
- return;
- }
- $fields = civicrm_api($entity, 'getfields', array('version' => 3, 'action' => $action));
- $fields = array_intersect_key($fields['values'], $params);
+function _civicrm_api3_validate_fields($entity, $action, &$params, $fields, $errorMode = False) {
+ $fields = array_intersect_key($fields, $params);
foreach ($fields as $fieldName => $fieldInfo) {
switch (CRM_Utils_Array::value('type', $fieldInfo)) {
case CRM_Utils_Type::T_INT:
break;
case CRM_Utils_Type::T_MONEY:
- if (!CRM_Utils_Rule::money($params[$fieldName])) {
+ if (!CRM_Utils_Rule::money($params[$fieldName]) && !empty($params[$fieldName])) {
throw new Exception($fieldName . " is not a valid amount: " . $params[$fieldName]);
}
}
*
* @param array $params params from civicrm_api
* @param string $fieldName uniquename of field being checked
- * @param array $fieldinfo array of fields from getfields function
+ * @param $fieldInfo
+ * @throws Exception
+ * @internal param array $fieldinfo array of fields from getfields function
*/
function _civicrm_api3_validate_date(&$params, &$fieldName, &$fieldInfo) {
//should we check first to prevent it from being copied if they have passed in sql friendly format?
*
* @param array $params params from civicrm_api
* @param string $fieldName uniquename of field being checked
- * @param array $fieldinfo array of fields from getfields function
+ * @param $fieldInfo
+ * @throws Exception
+ * @internal param array $fieldinfo array of fields from getfields function
*/
function _civicrm_api3_validate_constraint(&$params, &$fieldName, &$fieldInfo) {
$dao = new $fieldInfo['FKClassName'];
*
* @param array $params params from civicrm_api
* @param string $fieldName uniquename of field being checked
- * @param array $fieldinfo array of fields from getfields function
+ * @param $fieldInfo
+ * @throws Exception
+ * @internal param array $fieldinfo array of fields from getfields function
*/
function _civicrm_api3_validate_uniquekey(&$params, &$fieldName, &$fieldInfo) {
$existing = civicrm_api($params['entity'], 'get', array(
* @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
+ * @return array|int
*/
function _civicrm_api3_generic_replace($entity, $params) {
}
// Extract the keys -- somewhat scary, don't think too hard about it
- $baseParams = $params;
- unset($baseParams['values']);
- unset($baseParams['sequential']);
+ $baseParams = _civicrm_api3_generic_replace_base_params($params);
// Lookup pre-existing records
$preexisting = civicrm_api($entity, 'get', $baseParams, $params);
}
}
+/**
+ * @param $params
+ *
+ * @return mixed
+ */
+function _civicrm_api3_generic_replace_base_params($params) {
+ $baseParams = $params;
+ unset($baseParams['values']);
+ unset($baseParams['sequential']);
+ unset($baseParams['options']);
+ return $baseParams;
+}
+
/**
* returns fields allowable by api
+ *
* @param $entity string Entity to query
* @param bool $unique index by unique fields?
+ * @param array $params
+ *
+ * @return array
*/
function _civicrm_api_get_fields($entity, $unique = FALSE, &$params = array(
)) {
$customfields = array();
$entity = _civicrm_api_get_camel_name($entity);
if (strtolower($entity) == 'contact') {
+ // Use sub-type if available, otherwise stick with 'Contact'
$entity = CRM_Utils_Array::value('contact_type', $params);
}
$retrieveOnlyParent = FALSE;
foreach ($customfields as $key => $value) {
// Regular fields have a 'name' property
$value['name'] = 'custom_' . $key;
+ $value['type'] = _getStandardTypeFromCustomDataType($value['data_type']);
$customfields['custom_' . $key] = $value;
if (in_array('custom_' . $key, $getoptions)) {
$customfields['custom_' . $key]['options'] = CRM_Core_BAO_CustomOption::valuesByID($key);
}
return $customfields;
}
-
+/**
+ * Translate the custom field data_type attribute into a std 'type'
+ */
+function _getStandardTypeFromCustomDataType($dataType) {
+ $mapping = array(
+ 'String' => CRM_Utils_Type::T_STRING,
+ 'Int' => CRM_Utils_Type::T_INT,
+ 'Money' => CRM_Utils_Type::T_MONEY,
+ 'Memo' => CRM_Utils_Type::T_LONGTEXT,
+ 'Float' => CRM_Utils_Type::T_FLOAT,
+ 'Date' => CRM_Utils_Type::T_DATE,
+ 'Boolean' => CRM_Utils_Type::T_BOOLEAN,
+ 'StateProvince' => CRM_Utils_Type::T_INT,
+ 'File' => CRM_Utils_Type::T_STRING,
+ 'Link' => CRM_Utils_Type::T_STRING,
+ 'ContactReference' => CRM_Utils_Type::T_INT,
+ 'Country' => CRM_Utils_Type::T_INT,
+ );
+ return $mapping[$dataType];
+}
/**
* Return array of defaults for the given API (function is a wrapper on getfields)
*/
-function _civicrm_api3_getdefaults($apiRequest) {
+function _civicrm_api3_getdefaults($apiRequest, $fields) {
$defaults = array();
- $result = civicrm_api($apiRequest['entity'],
- 'getfields',
- array(
- 'version' => 3,
- 'action' => $apiRequest['action'],
- )
- );
-
- foreach ($result['values'] as $field => $values) {
+ foreach ($fields as $field => $values) {
if (isset($values['api.default'])) {
$defaults[$field] = $values['api.default'];
}
/**
* Return array of defaults for the given API (function is a wrapper on getfields)
*/
-function _civicrm_api3_getrequired($apiRequest) {
+function _civicrm_api3_getrequired($apiRequest, $fields) {
$required = array('version');
- $result = civicrm_api($apiRequest['entity'],
- 'getfields',
- array(
- 'version' => 3,
- 'action' => $apiRequest['action'],
- )
- );
- foreach ($result['values'] as $field => $values) {
+ foreach ($fields as $field => $values) {
if (CRM_Utils_Array::value('api.required', $values)) {
$required[] = $field;
}
*
* Function also swaps unique fields for non-unique fields & vice versa.
*/
-function _civicrm_api3_swap_out_aliases(&$apiRequest) {
- if (strtolower($apiRequest['action'] == 'getfields')) {
- if (CRM_Utils_Array::value('api_action', $apiRequest['params'])) {
- $apiRequest['params']['action'] = $apiRequest['params']['api_action'];
- unset($apiRequest['params']['api_action']);
- }
- return;
- }
- $result = civicrm_api($apiRequest['entity'],
- 'getfields',
- array(
- 'version' => 3,
- 'action' => $apiRequest['action'],
- )
- );
-
- foreach ($result['values'] as $field => $values) {
+function _civicrm_api3_swap_out_aliases(&$apiRequest, $fields) {
+ foreach ($fields as $field => $values) {
$uniqueName = CRM_Utils_Array::value('uniqueName', $values);
if (CRM_Utils_Array::value('api.aliases', $values)) {
// if aliased field is not set we try to use field alias
*
* @param array $params params from civicrm_api
* @param string $fieldName uniquename of field being checked
- * @param array $fieldinfo array of fields from getfields function
+ * @param $fieldInfo
+ * @param $entity
+ * @throws API_Exception
+ * @internal param array $fieldinfo array of fields from getfields function
*/
function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $entity) {
//if fieldname exists in params
return NULL;
}
+/**
+ * Validate html (check for scripting attack)
+ * @param $params
+ * @param $fieldName
+ * @param $fieldInfo
+ *
+ * @throws API_Exception
+ */
function _civicrm_api3_validate_html(&$params, &$fieldName, &$fieldInfo) {
if ($value = CRM_Utils_Array::value($fieldName, $params)) {
if (!CRM_Utils_Rule::xssString($value)) {
* Validate string fields being passed into API.
* @param array $params params from civicrm_api
* @param string $fieldName uniquename of field being checked
- * @param array $fieldinfo array of fields from getfields function
+ * @param $fieldInfo
+ * @param $entity
+ * @throws API_Exception
+ * @throws Exception
+ * @internal param array $fieldinfo array of fields from getfields function
*/
function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $entity) {
// If fieldname exists in params
function _civicrm_api3_api_match_pseudoconstant(&$params, $entity, $fieldName, $fieldInfo) {
$options = CRM_Utils_Array::value('options', $fieldInfo);
if (!$options) {
+ if(strtolower($entity) == 'profile' && !empty($fieldInfo['entity'])) {
+ // 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 = CRM_Utils_Array::value('values', $options, array());
}
- // If passed a value-seperated 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($params[$fieldName]) && strpos($params[$fieldName], CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) {
$params[$fieldName] = CRM_Utils_Array::explodePadded($params[$fieldName]);
* @param $value: field value
* @param $options: array of options for this field
* @param $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) {
// If option is a key, no need to translate