X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=api%2Fv3%2Futils.php;h=a9f0762464574c4725bc39a2ed55b0e7378a0e49;hb=7fbb4198d03adaf0b536941641b438103998efa3;hp=4c8ea1782f1bbc6ea91f0f7958e23d882630ebe4;hpb=c481c79f3eb67c0072267e62709cfb65d708702c;p=civicrm-core.git diff --git a/api/v3/utils.php b/api/v3/utils.php index 4c8ea1782f..a9f0762464 100644 --- a/api/v3/utils.php +++ b/api/v3/utils.php @@ -1,6 +1,4 @@ selectAdd(); $options['return']['id'] = TRUE;// ensure 'id' is included $allfields = _civicrm_api3_get_unique_name_array($dao); @@ -603,6 +596,7 @@ function _civicrm_api3_apply_filters_to_dao($filterField, $filterValue, &$dao) { * @return array $options options extracted from params */ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $entity = '', $action = '') { + $is_count = FALSE; $sort = CRM_Utils_Array::value('sort', $params, 0); $sort = CRM_Utils_Array::value('option.sort', $params, $sort); $sort = CRM_Utils_Array::value('option_sort', $params, $sort); @@ -617,6 +611,8 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $ $limit = CRM_Utils_Array::value('option_limit', $params, $limit); if (is_array(CRM_Utils_Array::value('options', $params))) { + // is count is set by generic getcount not user + $is_count = CRM_Utils_Array::value('is_count', $params['options']); $offset = CRM_Utils_Array::value('offset', $params['options'], $offset); $limit = CRM_Utils_Array::value('limit', $params['options'], $limit); $sort = CRM_Utils_Array::value('sort', $params['options'], $sort); @@ -651,8 +647,10 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $ 'offset' => $offset, 'sort' => $sort, 'limit' => $limit, + 'is_count' => $is_count, 'return' => !empty($returnProperties) ? $returnProperties : NULL, ); + if (!$queryObject) { return $options; } @@ -688,9 +686,11 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = FALSE, $ function _civicrm_api3_apply_options_to_dao(&$params, &$dao, $entity) { $options = _civicrm_api3_get_options_from_params($params,FALSE,$entity); - $dao->limit((int)$options['offset'], (int)$options['limit']); - if (!empty($options['sort'])) { - $dao->orderBy($options['sort']); + if(!$options['is_count']) { + $dao->limit((int)$options['offset'], (int)$options['limit']); + if (!empty($options['sort'])) { + $dao->orderBy($options['sort']); + } } } @@ -737,10 +737,16 @@ function _civicrm_api3_get_unique_name_array(&$bao) { */ function _civicrm_api3_dao_to_array($dao, $params = NULL, $uniqueFields = TRUE, $entity = "") { $result = array(); + if(isset($params['options']) && CRM_Utils_Array::value('is_count', $params['options'])) { + return $dao->count(); + } if (empty($dao) || !$dao->find()) { return array(); } + 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) && CRM_Utils_Array::value('return', $params) && is_array($params['return'])) { foreach ($params['return'] as $return) { @@ -931,7 +937,7 @@ function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $ $bao = new $bao_name(); _civicrm_api3_dao_set_filter($bao, $params, TRUE,$entity); if ($returnAsSuccess) { - return civicrm_api3_create_success(_civicrm_api3_dao_to_array($bao, $params, FALSE, $entity), $params, $entity); + return civicrm_api3_create_success(_civicrm_api3_dao_to_array($bao, $params, FALSE, $entity), $params, $entity); } else { return _civicrm_api3_dao_to_array($bao, $params, FALSE, $entity); @@ -947,22 +953,28 @@ function _civicrm_api3_basic_get($bao_name, &$params, $returnAsSuccess = TRUE, $ function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) { $args = array(&$params); - if(!empty($entity)){ + if (!empty($entity)) { $ids = array($entity => CRM_Utils_Array::value('id', $params)); $args[] = &$ids; } + if (method_exists($bao_name, 'create')) { $fct = 'create'; + $fct_name = $bao_name . '::' . $fct; + $bao = call_user_func_array(array($bao_name, $fct), $args); } elseif (method_exists($bao_name, 'add')) { $fct = 'add'; + $fct_name = $bao_name . '::' . $fct; + $bao = call_user_func_array(array($bao_name, $fct), $args); } - if (!isset($fct)) { - return civicrm_api3_create_error('Entity not created, missing create or add method for ' . $bao_name); + else { + $fct_name = '_civicrm_api3_basic_create_fallback'; + $bao = _civicrm_api3_basic_create_fallback($bao_name, $params); } - $bao = call_user_func_array(array($bao_name, $fct), $args); + if (is_null($bao)) { - return civicrm_api3_create_error('Entity not created ' . $bao_name . '::' . $fct); + return civicrm_api3_create_error('Entity not created (' . $fct_name . ')'); } else { $values = array(); @@ -971,6 +983,34 @@ function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) { } } +/** + * For BAO's which don't have a create() or add() functions, use this fallback implementation. + * + * FIXME There's an intuitive sense that this behavior should be defined somehow in the BAO/DAO class + * structure. In practice, that requires a fair amount of refactoring and/or kludgery. + * + * @param string $bao_name + * @param array $params + * @return CRM_Core_DAO|NULL an instance of the BAO + */ +function _civicrm_api3_basic_create_fallback($bao_name, &$params) { + $entityName = CRM_Core_DAO_AllCoreTables::getBriefName(get_parent_class($bao_name)); + if (empty($entityName)) { + throw new API_Exception("Class \"$bao_name\" does not map to an entity name", "unmapped_class_to_entity", array( + 'class_name' => $bao_name, + )); + } + $hook = empty($params['id']) ? 'create' : 'edit'; + + CRM_Utils_Hook::pre($hook, $entityName, CRM_Utils_Array::value('id', $params), $params); + $instance = new $bao_name(); + $instance->copyValues($params); + $instance->save(); + CRM_Utils_Hook::post($hook, $entityName, $instance->id, $instance); + + return $instance; +} + /** * Function to do a 'standard' api del - when the api is only doing a $bao::del then use this * if api::del doesn't exist it will try DAO delete method @@ -984,7 +1024,7 @@ function _civicrm_api3_basic_delete($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(); @@ -996,11 +1036,11 @@ function _civicrm_api3_basic_delete($bao_name, &$params) { } } 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'); } /** @@ -1447,10 +1487,14 @@ function _civicrm_api3_swap_out_aliases(&$apiRequest) { function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $entity) { //if fieldname exists in params if (CRM_Utils_Array::value($fieldName, $params)) { - //if value = 'user_contact_id' replace value with logged in user id - if ($params[$fieldName] == "user_contact_id") { - $session = &CRM_Core_Session::singleton(); - $params[$fieldName] = $session->get('userID'); + // if value = 'user_contact_id' (or similar), replace value with contact id + if (!is_numeric($params[$fieldName]) && is_scalar($params[$fieldName])) { + $realContactId = _civicrm_api3_resolve_contactID($params[$fieldName]); + if ('unknown-user' === $realContactId) { + throw new API_Exception("\"$fieldName\" \"{$params[$fieldName]}\" cannot be resolved to a contact ID", 2002, array('error_field' => $fieldName,"type"=>"integer")); + } elseif (is_numeric($realContactId)) { + $params[$fieldName] = $realContactId; + } } if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) { _civicrm_api3_api_match_pseudoconstant($params, $entity, $fieldName, $fieldInfo); @@ -1475,10 +1519,42 @@ function _civicrm_api3_validate_integer(&$params, &$fieldName, &$fieldInfo, $ent } } +/** + * 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 ($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)) { + $config = CRM_Core_Config::singleton(); + + $ufID = $config->userSystem->getUfId($matches[1]); + if (!$ufID) { + return 'unknown-user'; + } + + $contactID = CRM_Core_BAO_UFMatch::getContactId($ufID); + if (!$contactID) { + return 'unknown-user'; + } + + return $contactID; + } + return NULL; +} + function _civicrm_api3_validate_html(&$params, &$fieldName, &$fieldInfo) { if ($value = CRM_Utils_Array::value($fieldName, $params)) { if (!CRM_Utils_Rule::xssString($value)) { - throw new API_Exception('Illegal characters in input (potential scripting attack)',array("field"=>$fieldName,"error_code"=>"xss")); + throw new API_Exception('Illegal characters in input (potential scripting attack)', array("field"=>$fieldName,"error_code"=>"xss")); } } } @@ -1509,7 +1585,7 @@ function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $enti throw new Exception("Currency not a valid code: $value"); } } - if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) { + if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options']) || !empty($fieldInfo['enumValues'])) { _civicrm_api3_api_match_pseudoconstant($params, $entity, $fieldName, $fieldInfo); } // Check our field length @@ -1609,6 +1685,9 @@ function _civicrm_api3_api_resolve_alias($entity, $fieldName) { 'action' => 'create', )); $meta = $result['values']; + if (!isset($meta[$fieldName]['name']) && isset($meta[$fieldName . '_id'])) { + $fieldName = $fieldName . '_id'; + } if (isset($meta[$fieldName])) { return $meta[$fieldName]['name']; }