CRM-14370 - API Kernel - Extract XDebugSubscriber
[civicrm-core.git] / Civi / API / Kernel.php
CommitLineData
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*/
27namespace Civi\API;
28
132ec342
TO
29use Civi\API\Event\AuthorizeEvent;
30use Civi\API\Event\PrepareEvent;
31use Civi\API\Event\ExceptionEvent;
32use Civi\API\Event\RespondEvent;
33
34
0f643fb2
TO
35/**
36 *
37 * @package Civi
38 * @copyright CiviCRM LLC (c) 2004-2013
39 */
40
41class 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
77 $apiWrappers = array(
78 \CRM_Utils_API_HTMLInputCoder::singleton(),
79 \CRM_Utils_API_NullOutputCoder::singleton(),
80 \CRM_Utils_API_ReloadOption::singleton(),
81 \CRM_Utils_API_MatchOption::singleton(),
82 );
83 \CRM_Utils_Hook::apiWrappers($apiWrappers, $apiRequest);
84
85 try {
0f643fb2
TO
86 if (!is_array($params)) {
87 throw new \API_Exception('Input variable `params` is not an array', 2000);
88 }
132ec342
TO
89
90 $this->boot();
0f643fb2 91 $errorScope = \CRM_Core_TemporaryErrorScope::useException();
132ec342 92
0f643fb2
TO
93 // look up function, file, is_generic
94 $apiRequest += _civicrm_api_resolve($apiRequest);
132ec342
TO
95
96 if (! $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent(NULL, $apiRequest))->isAuthorized()) {
97 throw new \API_Exception("Authorization failed");
98 }
99
100 $apiRequest = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent(NULL, $apiRequest))->getApiRequest();
101
0f643fb2
TO
102 // support multi-lingual requests
103 if ($language = \CRM_Utils_Array::value('option.language', $params)) {
104 _civicrm_api_set_locale($language);
105 }
106
107 _civicrm_api3_api_check_permission($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
108 $fields = _civicrm_api3_api_getfields($apiRequest);
109 // we do this before we
110 _civicrm_api3_swap_out_aliases($apiRequest, $fields);
111 if (strtolower($action) != 'getfields') {
112 if (empty($apiRequest['params']['id'])) {
113 $apiRequest['params'] = array_merge(_civicrm_api3_getdefaults($apiRequest, $fields), $apiRequest['params']);
114 }
115 //if 'id' is set then only 'version' will be checked but should still be checked for consistency
116 civicrm_api3_verify_mandatory($apiRequest['params'], NULL, _civicrm_api3_getrequired($apiRequest, $fields));
117 }
118
119 // For input filtering, process $apiWrappers in forward order
120 foreach ($apiWrappers as $apiWrapper) {
121 $apiRequest = $apiWrapper->fromApiInput($apiRequest);
122 }
123
124 $function = $apiRequest['function'];
125 if ($apiRequest['function'] && $apiRequest['is_generic']) {
126 // Unlike normal API implementations, generic implementations require explicit
127 // knowledge of the entity and action (as well as $params). Bundle up these bits
128 // into a convenient data structure.
129 $result = $function($apiRequest);
130 }
131 elseif ($apiRequest['function'] && !$apiRequest['is_generic']) {
132 _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $fields);
133
134 $result = isset($extra) ? $function($apiRequest['params'], $extra) : $function($apiRequest['params']);
135 }
136 else {
137 return civicrm_api3_create_error("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
138 }
139
140 // For output filtering, process $apiWrappers in reverse order
141 foreach (array_reverse($apiWrappers) as $apiWrapper) {
142 $result = $apiWrapper->toApiOutput($apiRequest, $result);
143 }
144
145 if (\CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
146 if ($result['is_error'] === 0) {
132ec342 147 // FIXME dispatch
0f643fb2
TO
148 return 1;
149 }
150 else {
132ec342 151 // FIXME dispatch
0f643fb2
TO
152 return 0;
153 }
154 }
155 if (!empty($apiRequest['params']['format.only_id']) && isset($result['id'])) {
132ec342 156 // FIXME dispatch
0f643fb2
TO
157 return $result['id'];
158 }
132ec342 159
0f643fb2
TO
160 if (\CRM_Utils_Array::value('is_error', $result, 0) == 0) {
161 _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']);
162 }
132ec342 163
132ec342
TO
164 $responseEvent = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent(NULL, $apiRequest, $result));
165 $result = $responseEvent->getResponse();
166
0f643fb2
TO
167 return $result;
168 } catch (PEAR_Exception $e) {
169 if (\CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
170 return 0;
171 }
172 $error = $e->getCause();
173 if ($error instanceof DB_Error) {
174 $data["error_code"] = DB::errorMessage($error->getCode());
175 $data["sql"] = $error->getDebugInfo();
176 }
177 if (!empty($apiRequest['params']['debug'])) {
178 if (method_exists($e, 'getUserInfo')) {
179 $data['debug_info'] = $error->getUserInfo();
180 }
181 if (method_exists($e, 'getExtraData')) {
182 $data['debug_info'] = $data + $error->getExtraData();
183 }
184 $data['trace'] = $e->getTraceAsString();
185 }
186 else {
187 $data['tip'] = "add debug=1 to your API call to have more info about the error";
188 }
189 $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest);
132ec342 190 $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest));
0f643fb2
TO
191 return $err;
192 }
193 catch (\API_Exception $e) {
194 if (!isset($apiRequest)) {
195 $apiRequest = array();
196 }
197 if (\CRM_Utils_Array::value('format.is_success', \CRM_Utils_Array::value('params', $apiRequest)) == 1) {
198 return 0;
199 }
200 $data = $e->getExtraParams();
201 $data['entity'] = \CRM_Utils_Array::value('entity', $apiRequest);
202 $data['action'] = \CRM_Utils_Array::value('action', $apiRequest);
203 $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
204 if (\CRM_Utils_Array::value('debug', \CRM_Utils_Array::value('params', $apiRequest))
205 && empty($data['trace']) // prevent recursion
206 ) {
207 $err['trace'] = $e->getTraceAsString();
208 }
132ec342 209 $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest));
0f643fb2
TO
210 return $err;
211 }
212 catch (\Exception $e) {
213 if (\CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
214 return 0;
215 }
216 $data = array();
217 $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
218 if (!empty($apiRequest['params']['debug'])) {
219 $err['trace'] = $e->getTraceAsString();
220 }
132ec342 221 $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest));
0f643fb2
TO
222 return $err;
223 }
224
225 }
132ec342
TO
226
227 public function boot() {
228 require_once ('api/v3/utils.php');
229 require_once 'api/Exception.php';
230 _civicrm_api3_initialize();
231 }
0f643fb2 232}