Commit | Line | Data |
---|---|---|
0f643fb2 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
4 | | CiviCRM version 4.4 | | |
5 | +--------------------------------------------------------------------+ | |
6 | | Copyright CiviCRM LLC (c) 2004-2013 | | |
7 | +--------------------------------------------------------------------+ | |
8 | | This file is a part of CiviCRM. | | |
9 | | | | |
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. | | |
13 | | | | |
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. | | |
18 | | | | |
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 | +--------------------------------------------------------------------+ | |
26 | */ | |
27 | namespace Civi\API; | |
28 | ||
132ec342 TO |
29 | use Civi\API\Event\AuthorizeEvent; |
30 | use Civi\API\Event\PrepareEvent; | |
31 | use Civi\API\Event\ExceptionEvent; | |
32 | use Civi\API\Event\RespondEvent; | |
33 | ||
34 | ||
0f643fb2 TO |
35 | /** |
36 | * | |
37 | * @package Civi | |
38 | * @copyright CiviCRM LLC (c) 2004-2013 | |
39 | */ | |
40 | ||
41 | class Kernel { | |
42 | ||
43 | /** | |
44 | * @var \Symfony\Component\EventDispatcher\EventDispatcher | |
45 | */ | |
46 | protected $dispatcher; | |
47 | ||
48 | /** | |
49 | * @var array<APIProviderInterface> | |
50 | */ | |
51 | protected $apiProviders; | |
52 | ||
53 | function __construct($dispatcher, $apiProviders = array()) { | |
54 | $this->apiProviders = $apiProviders; | |
55 | $this->dispatcher = $dispatcher; | |
56 | } | |
57 | ||
58 | /** | |
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 | |
65 | * @param null $extra | |
66 | * | |
67 | * @return array|int | |
68 | */ | |
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; | |
76 | ||
91798b7a | 77 | /** @var $apiWrappers array<\API_Wrapper> */ |
0f643fb2 TO |
78 | $apiWrappers = array( |
79 | \CRM_Utils_API_HTMLInputCoder::singleton(), | |
80 | \CRM_Utils_API_NullOutputCoder::singleton(), | |
81 | \CRM_Utils_API_ReloadOption::singleton(), | |
82 | \CRM_Utils_API_MatchOption::singleton(), | |
83 | ); | |
84 | \CRM_Utils_Hook::apiWrappers($apiWrappers, $apiRequest); | |
85 | ||
86 | try { | |
0f643fb2 TO |
87 | if (!is_array($params)) { |
88 | throw new \API_Exception('Input variable `params` is not an array', 2000); | |
89 | } | |
132ec342 TO |
90 | |
91 | $this->boot(); | |
0f643fb2 | 92 | $errorScope = \CRM_Core_TemporaryErrorScope::useException(); |
132ec342 | 93 | |
0f643fb2 TO |
94 | // look up function, file, is_generic |
95 | $apiRequest += _civicrm_api_resolve($apiRequest); | |
132ec342 TO |
96 | |
97 | if (! $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent(NULL, $apiRequest))->isAuthorized()) { | |
98 | throw new \API_Exception("Authorization failed"); | |
99 | } | |
100 | ||
101 | $apiRequest = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent(NULL, $apiRequest))->getApiRequest(); | |
102 | ||
0f643fb2 TO |
103 | // support multi-lingual requests |
104 | if ($language = \CRM_Utils_Array::value('option.language', $params)) { | |
105 | _civicrm_api_set_locale($language); | |
106 | } | |
107 | ||
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']); | |
115 | } | |
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)); | |
118 | } | |
119 | ||
120 | // For input filtering, process $apiWrappers in forward order | |
121 | foreach ($apiWrappers as $apiWrapper) { | |
122 | $apiRequest = $apiWrapper->fromApiInput($apiRequest); | |
123 | } | |
124 | ||
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); | |
131 | } | |
132 | elseif ($apiRequest['function'] && !$apiRequest['is_generic']) { | |
133 | _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $fields); | |
134 | ||
135 | $result = isset($extra) ? $function($apiRequest['params'], $extra) : $function($apiRequest['params']); | |
136 | } | |
137 | else { | |
138 | return civicrm_api3_create_error("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)"); | |
139 | } | |
140 | ||
141 | // For output filtering, process $apiWrappers in reverse order | |
142 | foreach (array_reverse($apiWrappers) as $apiWrapper) { | |
143 | $result = $apiWrapper->toApiOutput($apiRequest, $result); | |
144 | } | |
145 | ||
146 | if (\CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) { | |
147 | if ($result['is_error'] === 0) { | |
132ec342 | 148 | // FIXME dispatch |
0f643fb2 TO |
149 | return 1; |
150 | } | |
151 | else { | |
132ec342 | 152 | // FIXME dispatch |
0f643fb2 TO |
153 | return 0; |
154 | } | |
155 | } | |
156 | if (!empty($apiRequest['params']['format.only_id']) && isset($result['id'])) { | |
132ec342 | 157 | // FIXME dispatch |
0f643fb2 TO |
158 | return $result['id']; |
159 | } | |
132ec342 | 160 | |
0f643fb2 TO |
161 | if (\CRM_Utils_Array::value('is_error', $result, 0) == 0) { |
162 | _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']); | |
163 | } | |
132ec342 | 164 | |
132ec342 TO |
165 | $responseEvent = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent(NULL, $apiRequest, $result)); |
166 | $result = $responseEvent->getResponse(); | |
167 | ||
0f643fb2 | 168 | return $result; |
0f643fb2 TO |
169 | } |
170 | catch (\Exception $e) { | |
91798b7a TO |
171 | $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest)); |
172 | ||
173 | if (isset($apiRequest, $apiRequest['params'], $apiRequest['params']['format.is_success']) && $apiRequest['params']['format.is_success'] == 1) { | |
0f643fb2 TO |
174 | return 0; |
175 | } | |
91798b7a TO |
176 | |
177 | if ($e instanceof \PEAR_Exception) { | |
178 | $err = $this->formatPearException($e, $apiRequest); | |
179 | } elseif ($e instanceof \API_Exception) { | |
180 | $err = $this->formatApiException($e, $apiRequest); | |
181 | } else { | |
182 | $err = $this->formatException($e, $apiRequest); | |
0f643fb2 | 183 | } |
91798b7a | 184 | |
0f643fb2 TO |
185 | return $err; |
186 | } | |
187 | ||
188 | } | |
132ec342 TO |
189 | |
190 | public function boot() { | |
191 | require_once ('api/v3/utils.php'); | |
192 | require_once 'api/Exception.php'; | |
193 | _civicrm_api3_initialize(); | |
194 | } | |
91798b7a TO |
195 | |
196 | /** | |
197 | * @param \Exception $e | |
198 | * @param array $apiRequest | |
199 | * @return array (API response) | |
200 | */ | |
201 | public function formatException($e, $apiRequest) { | |
202 | $data = array(); | |
203 | if (!empty($apiRequest['params']['debug'])) { | |
204 | $data['trace'] = $e->getTraceAsString(); | |
205 | } | |
206 | return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode()); | |
207 | } | |
208 | ||
209 | /** | |
210 | * @param \API_Exception $e | |
211 | * @param array $apiRequest | |
212 | * @return array (API response) | |
213 | */ | |
214 | public function formatApiException($e, $apiRequest) { | |
215 | $data = $e->getExtraParams(); | |
216 | $data['entity'] = \CRM_Utils_Array::value('entity', $apiRequest); | |
217 | $data['action'] = \CRM_Utils_Array::value('action', $apiRequest); | |
218 | ||
219 | if (\CRM_Utils_Array::value('debug', \CRM_Utils_Array::value('params', $apiRequest)) | |
220 | && empty($data['trace']) // prevent recursion | |
221 | ) { | |
222 | $data['trace'] = $e->getTraceAsString(); | |
223 | } | |
224 | ||
225 | return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode()); | |
226 | } | |
227 | ||
228 | /** | |
229 | * @param \PEAR_Exception $e | |
230 | * @param array $apiRequest | |
231 | * @return array (API response) | |
232 | */ | |
233 | public function formatPearException($e, $apiRequest) { | |
234 | $data = array(); | |
235 | $error = $e->getCause(); | |
236 | if ($error instanceof \DB_Error) { | |
237 | $data["error_code"] = \DB::errorMessage($error->getCode()); | |
238 | $data["sql"] = $error->getDebugInfo(); | |
239 | } | |
240 | if (!empty($apiRequest['params']['debug'])) { | |
241 | if (method_exists($e, 'getUserInfo')) { | |
242 | $data['debug_info'] = $error->getUserInfo(); | |
243 | } | |
244 | if (method_exists($e, 'getExtraData')) { | |
245 | $data['debug_info'] = $data + $error->getExtraData(); | |
246 | } | |
247 | $data['trace'] = $e->getTraceAsString(); | |
248 | } | |
249 | else { | |
250 | $data['tip'] = "add debug=1 to your API call to have more info about the error"; | |
251 | } | |
252 | ||
253 | return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest); | |
254 | } | |
0f643fb2 | 255 | } |