3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 use Civi\API\Event\AuthorizeEvent
;
30 use Civi\API\Event\PrepareEvent
;
31 use Civi\API\Event\ExceptionEvent
;
32 use Civi\API\Event\RespondEvent
;
38 * @copyright CiviCRM LLC (c) 2004-2013
44 * @var \Symfony\Component\EventDispatcher\EventDispatcher
46 protected $dispatcher;
49 * @var array<APIProviderInterface>
51 protected $apiProviders;
53 function __construct($dispatcher, $apiProviders = array()) {
54 $this->apiProviders
= $apiProviders;
55 $this->dispatcher
= $dispatcher;
59 * @param string $entity
60 * type of entities to deal with
61 * @param string $action
62 * create, get, delete or some special action name.
63 * @param array $params
64 * array to be passed to function
69 public function run($entity, $action, $params, $extra) {
70 $apiRequest = array();
71 $apiRequest['entity'] = \CRM_Utils_String
::munge($entity);
72 $apiRequest['action'] = \CRM_Utils_String
::munge($action);
73 $apiRequest['version'] = civicrm_get_api_version($params);
74 $apiRequest['params'] = $params;
75 $apiRequest['extra'] = $extra;
77 /** @var $apiWrappers array<\API_Wrapper> */
79 \CRM_Utils_API_HTMLInputCoder
::singleton(),
80 \CRM_Utils_API_NullOutputCoder
::singleton(),
81 \CRM_Utils_API_ReloadOption
::singleton(),
82 \CRM_Utils_API_MatchOption
::singleton(),
84 \CRM_Utils_Hook
::apiWrappers($apiWrappers, $apiRequest);
87 if (!is_array($params)) {
88 throw new \
API_Exception('Input variable `params` is not an array', 2000);
92 $errorScope = \CRM_Core_TemporaryErrorScope
::useException();
94 // look up function, file, is_generic
95 $apiRequest +
= _civicrm_api_resolve($apiRequest);
97 if (! $this->dispatcher
->dispatch(Events
::AUTHORIZE
, new AuthorizeEvent(NULL, $apiRequest))->isAuthorized()) {
98 throw new \
API_Exception("Authorization failed");
101 $apiRequest = $this->dispatcher
->dispatch(Events
::PREPARE
, new PrepareEvent(NULL, $apiRequest))->getApiRequest();
103 // support multi-lingual requests
104 if ($language = \CRM_Utils_Array
::value('option.language', $params)) {
105 _civicrm_api_set_locale($language);
108 _civicrm_api3_api_check_permission($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
109 $fields = _civicrm_api3_api_getfields($apiRequest);
110 // we do this before we
111 _civicrm_api3_swap_out_aliases($apiRequest, $fields);
112 if (strtolower($action) != 'getfields') {
113 if (empty($apiRequest['params']['id'])) {
114 $apiRequest['params'] = array_merge(_civicrm_api3_getdefaults($apiRequest, $fields), $apiRequest['params']);
116 //if 'id' is set then only 'version' will be checked but should still be checked for consistency
117 civicrm_api3_verify_mandatory($apiRequest['params'], NULL, _civicrm_api3_getrequired($apiRequest, $fields));
120 // For input filtering, process $apiWrappers in forward order
121 foreach ($apiWrappers as $apiWrapper) {
122 $apiRequest = $apiWrapper->fromApiInput($apiRequest);
125 $function = $apiRequest['function'];
126 if ($apiRequest['function'] && $apiRequest['is_generic']) {
127 // Unlike normal API implementations, generic implementations require explicit
128 // knowledge of the entity and action (as well as $params). Bundle up these bits
129 // into a convenient data structure.
130 $result = $function($apiRequest);
132 elseif ($apiRequest['function'] && !$apiRequest['is_generic']) {
133 _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $fields);
135 $result = isset($extra) ?
$function($apiRequest['params'], $extra) : $function($apiRequest['params']);
138 throw new \
API_Exception("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
141 // For output filtering, process $apiWrappers in reverse order
142 foreach (array_reverse($apiWrappers) as $apiWrapper) {
143 $result = $apiWrapper->toApiOutput($apiRequest, $result);
146 if (\CRM_Utils_Array
::value('is_error', $result, 0) == 0) {
147 _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']);
150 $responseEvent = $this->dispatcher
->dispatch(Events
::RESPOND
, new RespondEvent(NULL, $apiRequest, $result));
151 return $this->formatResult($apiRequest, $responseEvent->getResponse());
153 catch (\Exception
$e) {
154 $this->dispatcher
->dispatch(Events
::EXCEPTION
, new ExceptionEvent($e, NULL, $apiRequest));
156 if ($e instanceof \PEAR_Exception
) {
157 $err = $this->formatPearException($e, $apiRequest);
158 } elseif ($e instanceof \API_Exception
) {
159 $err = $this->formatApiException($e, $apiRequest);
161 $err = $this->formatException($e, $apiRequest);
164 return $this->formatResult($apiRequest, $err);
169 public function boot() {
170 require_once ('api/v3/utils.php');
171 require_once 'api/Exception.php';
172 _civicrm_api3_initialize();
176 * @param \Exception $e
177 * @param array $apiRequest
178 * @return array (API response)
180 public function formatException($e, $apiRequest) {
182 if (!empty($apiRequest['params']['debug'])) {
183 $data['trace'] = $e->getTraceAsString();
185 return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
189 * @param \API_Exception $e
190 * @param array $apiRequest
191 * @return array (API response)
193 public function formatApiException($e, $apiRequest) {
194 $data = $e->getExtraParams();
195 $data['entity'] = \CRM_Utils_Array
::value('entity', $apiRequest);
196 $data['action'] = \CRM_Utils_Array
::value('action', $apiRequest);
198 if (\CRM_Utils_Array
::value('debug', \CRM_Utils_Array
::value('params', $apiRequest))
199 && empty($data['trace']) // prevent recursion
201 $data['trace'] = $e->getTraceAsString();
204 return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
208 * @param \PEAR_Exception $e
209 * @param array $apiRequest
210 * @return array (API response)
212 public function formatPearException($e, $apiRequest) {
214 $error = $e->getCause();
215 if ($error instanceof \DB_Error
) {
216 $data["error_code"] = \DB
::errorMessage($error->getCode());
217 $data["sql"] = $error->getDebugInfo();
219 if (!empty($apiRequest['params']['debug'])) {
220 if (method_exists($e, 'getUserInfo')) {
221 $data['debug_info'] = $error->getUserInfo();
223 if (method_exists($e, 'getExtraData')) {
224 $data['debug_info'] = $data +
$error->getExtraData();
226 $data['trace'] = $e->getTraceAsString();
229 $data['tip'] = "add debug=1 to your API call to have more info about the error";
232 return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest);
238 public function formatResult($apiRequest, $result) {
239 if (isset($apiRequest, $apiRequest['params'])) {
240 if (isset($apiRequest['params']['format.is_success']) && $apiRequest['params']['format.is_success'] == 1) {
241 return (empty($result['is_error'])) ?
1 : 0;
244 if (!empty($apiRequest['params']['format.only_id']) && isset($result['id'])) {
246 return $result['id'];