*
* @param <type> $data
* @param array $data
- * @param array $dao (misnomer) apiRequest which led to this error (with keys "entity", "action", etc)
*
* @throws API_Exception
* @return array <type>
*/
-function civicrm_api3_create_error($msg, $data = array(), &$dao = NULL) {
- if (is_array($dao)) {
- if ($msg == 'DB Error: constraint violation' || substr($msg, 0,9) == 'DB Error:' || $msg == 'DB Error: already exists') {
- try {
- $fields = _civicrm_api3_api_getfields($dao);
- _civicrm_api3_validate_fields($dao['entity'], $dao['action'], $dao['params'], $fields, TRUE);
- }
- catch(Exception $e) {
- $msg = $e->getMessage();
- }
- }
- }
+function civicrm_api3_create_error($msg, $data = array()) {
$data['is_error'] = 1;
$data['error_message'] = $msg;
- // we will show sql to privelledged user only (not sure of a specific
- // security hole here but seems sensible - perhaps should apply to the trace as well?
+ // 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?
} else {
unset($data['sql']);
}
- if (is_array($dao) && isset($dao['params']) && is_array($dao['params']) && !empty($dao['params']['api.has_parent'])) {
- $errorCode = empty($data['error_code']) ? 'chained_api_failed' : $data['error_code'];
- throw new API_Exception('Error in call to ' . $dao['entity'] . '_' . $dao['action'] . ' : ' . $msg, $errorCode, $data);
- }
return $data;
}
$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'));
+ $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);
}
}
if(!empty($params['options']['metadata'])) {
// we've made metadata an array but only supporting 'fields' atm
- if(in_array('fields', $params['options']['metadata'])) {
+ if(in_array('fields', (array) $params['options']['metadata'])) {
$fields = civicrm_api3($entity, 'getfields', array('action' => substr($action, 0, 3) == 'get' ? 'get' : 'create'));
$result['metadata']['fields'] = $fields['values'];
}
// len ('civicrm_api3_') == 13
$name = substr($name, 13, $last - 13);
}
-
+
$name = _civicrm_api_get_camel_name($name, 3);
if ($name == 'Individual' || $name == 'Household' || $name == 'Organization') {
}
}
+
$skipPermissions = !empty($params['check_permissions']) ? 0 :1;
list($entities, $options) = CRM_Contact_BAO_Query::apiQuery(
}
}
}
- // http://issues.civicrm.org/jira/browse/CRM-9150 - stick with 'simple' operators for now
- // support for other syntaxes is discussed in ticket but being put off for now
- $acceptedSQLOperators = array('=', '<=', '>=', '>', '<', 'LIKE', "<>", "!=", "NOT LIKE", 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN');
if (!$fields) {
$fields = array();
}
* @param string $entity
* @param string $action
*
+ * @throws API_Exception
* @return array $options options extracted from params
*/
function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $entity = '', $action = '') {
'sort' => CRM_Utils_Rule::string($sort) ? $sort : NULL,
'limit' => CRM_Utils_Rule::integer($limit) ? $limit : NULL,
'is_count' => $is_count,
- 'return' => !empty($returnProperties) ? $returnProperties : NULL,
+ 'return' => !empty($returnProperties) ? $returnProperties : array(),
);
if ($options['sort'] && stristr($options['sort'], 'SELECT')) {
/**
* 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
*
+ * @param bool $autoFind
+ *
* @return array
*
* @params array of arrays (key = id) of array of fields
if(isset($dao->count)) {
return $dao->count;
}
- //if custom fields are required we will endeavour to set them . NB passing $entity in might be a bit clunky / unrequired
- if (!empty($entity) && !empty($params['return']) && is_array($params['return'])) {
- foreach ($params['return'] as $return) {
- if (substr($return, 0, 6) == 'custom') {
- $custom = TRUE;
- }
- }
- }
-
$fields = array_keys(_civicrm_api3_build_fields_array($dao, $uniqueFields));
}
}
$result[$dao->id] = $tmp;
- if (!empty($custom)) {
+
+ if(_civicrm_api3_custom_fields_are_required($entity, $params)) {
_civicrm_api3_custom_data_get($result[$dao->id], $entity, $dao->id);
}
}
return $result;
}
+/**
+ * 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
+ *
+ * @param $params
+ * @param string $entity - entity name in CamelCase
+ *
+ * @return bool
+ */
+function _civicrm_api3_custom_fields_are_required($entity, $params) {
+ if (!array_key_exists($entity, CRM_Core_BAO_CustomQuery::$extendsMap)) {
+ return FALSE;
+ }
+ $options = _civicrm_api3_get_options_from_params($params);
+ //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
*
}
}
+/**
+ * @param $params
+ * @param $entity
+ */
+function _civicrm_api3_format_params_for_create(&$params, $entity) {
+ $nonGenericEntities = array('Contact', 'Individual', 'Household', 'Organization');
+
+ $customFieldEntities = array_diff_key(CRM_Core_BAO_CustomQuery::$extendsMap, array_fill_keys($nonGenericEntities, 1));
+ if(!array_key_exists($entity, $customFieldEntities)) {
+ return;
+ }
+ $values = array();
+ _civicrm_api3_custom_format_params($params, $values, $entity);
+ $params = array_merge($params, $values);
+}
+
/**
* @deprecated
* This function ensures that we have the right input parameters
return TRUE;
}
-/**
- * Check permissions for a given API call.
- *
- * @param $entity string API entity being accessed
- * @param $action string API action being performed
- * @param $params array params of the API call
- * @param $throw deprecated 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) {
- // return early unless we’re told explicitly to do the permission check
- if (empty($params['check_permissions']) or $params['check_permissions'] == FALSE) {
- return TRUE;
- }
-
- require_once 'CRM/Core/DAO/permissions.php';
- $permissions = _civicrm_api3_permissions($entity, $action, $params);
-
- // $params might’ve been reset by the alterAPIPermissions() hook
- if (isset($params['check_permissions']) and $params['check_permissions'] == FALSE) {
- return TRUE;
- }
-
- if (!CRM_Core_Permission::check($permissions)) {
- if ($throw) {
- if(is_array($permissions)) {
- $permissions = implode(' and ', $permissions);
- }
- throw new Exception("API permission check failed for $entity/$action call; insufficient permission: require $permissions");
- }
- else {
- //@todo remove this - this is an internal api function called with $throw set to TRUE. It is only called with false
- // in tests & that should be tidied up
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
/**
* Function to do a 'standard' api get - when the api is only doing a $bao->find then use this
*
return civicrm_api3_create_success(_civicrm_api3_dao_to_array($bao, $params, FALSE, $entity), $params, $entity, 'get');
}
else {
- return _civicrm_api3_dao_to_array($bao, $params, FALSE, $entity);
+ return _civicrm_api3_dao_to_array($bao, $params, FALSE, $entity, 'get');
}
}
/**
* 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
* @param array $params parameters passed into the api call
* @param string $entity Entity - pass in if entity is non-standard & required $ids array
+ *
+ * @throws API_Exception
* @return array
*/
function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
-
+ _civicrm_api3_format_params_for_create($params, $entity);
$args = array(&$params);
if (!empty($entity)) {
$ids = array($entity => CRM_Utils_Array::value('id', $params));
* @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,
+ $groupTree = CRM_Core_BAO_CustomGroup::getTree($entity,
CRM_Core_DAO::$_nullObject,
$entity_id,
$groupID,
if (strtotime($params[$fieldInfo['name']]) === FALSE) {
throw new Exception($fieldInfo['name'] . " is not a valid date: " . $params[$fieldInfo['name']]);
}
- $params[$fieldInfo['name']] = CRM_Utils_Date::processDate($params[$fieldInfo['name']]);
+ $format = ($fieldInfo['type'] == CRM_Utils_Type::T_DATE) ? 'Ymd000000' : 'YmdHis';
+ $params[$fieldInfo['name']] = CRM_Utils_Date::processDate($params[$fieldInfo['name']], NULL, FALSE, $format);
}
if ((CRM_Utils_Array::value('name', $fieldInfo) != $fieldName) && !empty($params[$fieldName])) {
//If the unique field name differs from the db name & is set handle it here
// an entry already exists for this unique field
if ($existing['count'] == 1) {
// question - could this ever be a security issue?
- throw new Exception("Field: `$fieldName` must be unique. An conflicting entity already exists - id: " . $existing['id']);
+ throw new API_Exception("Field: `$fieldName` must be unique. An conflicting entity already exists - id: " . $existing['id']);
}
}
FALSE,
FALSE
);
- // find out if we have any requests to resolve options
- $getoptions = CRM_Utils_Array::value('get_options', CRM_Utils_Array::value('options',$params));
- if(!is_array($getoptions)){
- $getoptions = array($getoptions);
- }
+
+ $ret = array();
foreach ($customfields as $key => $value) {
// Regular fields have a 'name' property
$value['name'] = 'custom_' . $key;
+ $value['title'] = $value['label'];
$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);
- }
- unset($customfields[$key]);
+ $ret['custom_' . $key] = $value;
}
- return $customfields;
+ return $ret;
}
/**
* Translate the custom field data_type attribute into a std 'type'
);
return $mapping[$dataType];
}
-/**
- * Return array of defaults for the given API (function is a wrapper on getfields)
- */
-function _civicrm_api3_getdefaults($apiRequest, $fields) {
- $defaults = array();
- foreach ($fields as $field => $values) {
- if (isset($values['api.default'])) {
- $defaults[$field] = $values['api.default'];
- }
- }
- return $defaults;
-}
-
-/**
- * Return array of defaults for the given API (function is a wrapper on getfields)
- */
-function _civicrm_api3_getrequired($apiRequest, $fields) {
- $required = array('version');
-
- foreach ($fields as $field => $values) {
- if (!empty($values['api.required'])) {
- $required[] = $field;
- }
- }
- return $required;
-}
/**
* Fill params array with alternate (alias) values where a field has an alias and that is filled & the main field isn't
* @internal param array $fieldinfo array of fields from getfields function
*/
function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $entity) {
- //if fieldname exists in params
if (!empty($params[$fieldName])) {
// if value = 'user_contact_id' (or similar), replace value with contact id
if (!is_numeric($params[$fieldName]) && is_scalar($params[$fieldName])) {
function _civicrm_api3_resolve_contactID($contactIdExpr) {
//if value = 'user_contact_id' replace value with logged in user id
if ($contactIdExpr == "user_contact_id") {
- $session = &CRM_Core_Session::singleton();
- if (!is_numeric($session->get('userID'))) {
- return NULL;
- }
- return $session->get('userID');
- } elseif (preg_match('/^@user:(.*)$/', $contactIdExpr, $matches)) {
+ return CRM_Core_Session::getLoggedInContactID();
+ }
+ elseif (preg_match('/^@user:(.*)$/', $contactIdExpr, $matches)) {
$config = CRM_Core_Config::singleton();
$ufID = $config->userSystem->getUfId($matches[1]);