CRM-14370 - API Kernel - Add ProviderInterface. Extract MagicFunctionProvider.
[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;
787604ff 32use Civi\API\Event\ResolveEvent;
132ec342
TO
33use Civi\API\Event\RespondEvent;
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) {
787604ff
TO
70 /**
71 * @var $apiProvider \Civi\API\Provider\ProviderInterface|NULL
72 */
73 $apiProvider = NULL;
74
61c8f96f 75 $apiRequest = $this->createRequest($entity, $action, $params, $extra);
0f643fb2 76
0f643fb2 77 try {
0f643fb2
TO
78 if (!is_array($params)) {
79 throw new \API_Exception('Input variable `params` is not an array', 2000);
80 }
132ec342
TO
81
82 $this->boot();
0f643fb2 83 $errorScope = \CRM_Core_TemporaryErrorScope::useException();
132ec342 84
787604ff
TO
85 $resolveEvent = $this->dispatcher->dispatch(Events::RESOLVE, new ResolveEvent($apiRequest));
86 $apiRequest = $resolveEvent->getApiRequest();
87 $apiProvider = $resolveEvent->getApiProvider();
88 if (!$apiProvider) {
89 throw new \API_Exception("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
132ec342
TO
90 }
91
787604ff
TO
92 if (! $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent($apiProvider, $apiRequest))->isAuthorized()) {
93 throw new \API_Exception("Authorization failed", 'unauthorized');
0f643fb2
TO
94 }
95
787604ff
TO
96 $apiRequest = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent($apiProvider, $apiRequest))->getApiRequest();
97 $result = $apiProvider->invoke($apiRequest);
98
0f643fb2
TO
99 if (\CRM_Utils_Array::value('is_error', $result, 0) == 0) {
100 _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']);
101 }
132ec342 102
787604ff 103 $responseEvent = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent($apiProvider, $apiRequest, $result));
143ed725 104 return $this->formatResult($apiRequest, $responseEvent->getResponse());
0f643fb2
TO
105 }
106 catch (\Exception $e) {
787604ff 107 $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, $apiProvider, $apiRequest));
91798b7a 108
91798b7a
TO
109 if ($e instanceof \PEAR_Exception) {
110 $err = $this->formatPearException($e, $apiRequest);
111 } elseif ($e instanceof \API_Exception) {
112 $err = $this->formatApiException($e, $apiRequest);
113 } else {
114 $err = $this->formatException($e, $apiRequest);
0f643fb2 115 }
91798b7a 116
143ed725 117 return $this->formatResult($apiRequest, $err);
0f643fb2
TO
118 }
119
120 }
132ec342 121
61c8f96f
TO
122 /**
123 * Create a formatted/normalized request object.
124 *
125 * @param string $entity
126 * @param string $action
127 * @param array $params
128 * @param mixed $extra
129 * @return array the request descriptor
130 */
131 public function createRequest($entity, $action, $params, $extra) {
132 $apiRequest = array();
133 $apiRequest['entity'] = \CRM_Utils_String::munge($entity);
134 $apiRequest['action'] = \CRM_Utils_String::munge($action);
135 $apiRequest['version'] = civicrm_get_api_version($params);
136 $apiRequest['params'] = $params;
137 $apiRequest['extra'] = $extra;
138 $apiRequest['fields'] = NULL;
139 return $apiRequest;
140 }
141
132ec342
TO
142 public function boot() {
143 require_once ('api/v3/utils.php');
144 require_once 'api/Exception.php';
145 _civicrm_api3_initialize();
146 }
91798b7a
TO
147
148 /**
149 * @param \Exception $e
150 * @param array $apiRequest
151 * @return array (API response)
152 */
153 public function formatException($e, $apiRequest) {
154 $data = array();
155 if (!empty($apiRequest['params']['debug'])) {
156 $data['trace'] = $e->getTraceAsString();
157 }
158 return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
159 }
160
161 /**
162 * @param \API_Exception $e
163 * @param array $apiRequest
164 * @return array (API response)
165 */
166 public function formatApiException($e, $apiRequest) {
167 $data = $e->getExtraParams();
168 $data['entity'] = \CRM_Utils_Array::value('entity', $apiRequest);
169 $data['action'] = \CRM_Utils_Array::value('action', $apiRequest);
170
171 if (\CRM_Utils_Array::value('debug', \CRM_Utils_Array::value('params', $apiRequest))
172 && empty($data['trace']) // prevent recursion
173 ) {
174 $data['trace'] = $e->getTraceAsString();
175 }
176
177 return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
178 }
179
180 /**
181 * @param \PEAR_Exception $e
182 * @param array $apiRequest
183 * @return array (API response)
184 */
185 public function formatPearException($e, $apiRequest) {
186 $data = array();
187 $error = $e->getCause();
188 if ($error instanceof \DB_Error) {
189 $data["error_code"] = \DB::errorMessage($error->getCode());
190 $data["sql"] = $error->getDebugInfo();
191 }
192 if (!empty($apiRequest['params']['debug'])) {
193 if (method_exists($e, 'getUserInfo')) {
194 $data['debug_info'] = $error->getUserInfo();
195 }
196 if (method_exists($e, 'getExtraData')) {
197 $data['debug_info'] = $data + $error->getExtraData();
198 }
199 $data['trace'] = $e->getTraceAsString();
200 }
201 else {
202 $data['tip'] = "add debug=1 to your API call to have more info about the error";
203 }
204
205 return civicrm_api3_create_error($e->getMessage(), $data, $apiRequest);
206 }
143ed725
TO
207
208 /**
209 * @return mixed
210 */
211 public function formatResult($apiRequest, $result) {
212 if (isset($apiRequest, $apiRequest['params'])) {
213 if (isset($apiRequest['params']['format.is_success']) && $apiRequest['params']['format.is_success'] == 1) {
214 return (empty($result['is_error'])) ? 1 : 0;
215 }
216
217 if (!empty($apiRequest['params']['format.only_id']) && isset($result['id'])) {
218 // FIXME dispatch
219 return $result['id'];
220 }
221 }
222 return $result;
223 }
0f643fb2 224}