From 132ec34206eb8a58bb1a301a328ed624f03377c9 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 20 Mar 2014 22:34:30 -0700 Subject: [PATCH] CRM-14370 - API Kernel - Dispatch events --- Civi/API/Event/AuthorizeEvent.php | 46 +++++++++++++++++ Civi/API/Event/Event.php | 59 ++++++++++++++++++++++ Civi/API/Event/ExceptionEvent.php | 48 ++++++++++++++++++ Civi/API/Event/PrepareEvent.php | 39 +++++++++++++++ Civi/API/Event/RespondEvent.php | 54 ++++++++++++++++++++ Civi/API/Events.php | 83 +++++++++++++++++++++++++++++++ Civi/API/Kernel.php | 36 ++++++++++++-- Civi/Core/Container.php | 4 ++ 8 files changed, 366 insertions(+), 3 deletions(-) create mode 100644 Civi/API/Event/AuthorizeEvent.php create mode 100644 Civi/API/Event/Event.php create mode 100644 Civi/API/Event/ExceptionEvent.php create mode 100644 Civi/API/Event/PrepareEvent.php create mode 100644 Civi/API/Event/RespondEvent.php create mode 100644 Civi/API/Events.php diff --git a/Civi/API/Event/AuthorizeEvent.php b/Civi/API/Event/AuthorizeEvent.php new file mode 100644 index 0000000000..42b814db9a --- /dev/null +++ b/Civi/API/Event/AuthorizeEvent.php @@ -0,0 +1,46 @@ +authorized = TRUE; + } + + /** + * @return boolean + */ + public function isAuthorized() { + return $this->authorized; + } +} diff --git a/Civi/API/Event/Event.php b/Civi/API/Event/Event.php new file mode 100644 index 0000000000..91657fa272 --- /dev/null +++ b/Civi/API/Event/Event.php @@ -0,0 +1,59 @@ +apiProvider = $apiProvider; + $this->apiRequest = $apiRequest; + } + + /** + * @return object + */ + public function getApiProvider() { + return $this->apiProvider; + } + + /** + * @return array + */ + public function getApiRequest() { + return $this->apiRequest; + } +} diff --git a/Civi/API/Event/ExceptionEvent.php b/Civi/API/Event/ExceptionEvent.php new file mode 100644 index 0000000000..c7771eefbf --- /dev/null +++ b/Civi/API/Event/ExceptionEvent.php @@ -0,0 +1,48 @@ +exception = $exception; + parent::__construct($apiProvider, $apiRequest); + } + + /** + * @return \Exception + */ + public function getException() { + return $this->exception; + } +} diff --git a/Civi/API/Event/PrepareEvent.php b/Civi/API/Event/PrepareEvent.php new file mode 100644 index 0000000000..f7cf7dceaa --- /dev/null +++ b/Civi/API/Event/PrepareEvent.php @@ -0,0 +1,39 @@ +apiRequest = $apiRequest; + return $this; + } +} diff --git a/Civi/API/Event/RespondEvent.php b/Civi/API/Event/RespondEvent.php new file mode 100644 index 0000000000..e8fb548aa5 --- /dev/null +++ b/Civi/API/Event/RespondEvent.php @@ -0,0 +1,54 @@ +response = $response; + parent::__construct($apiProvider, $apiRequest); + } + + /** + * @return mixed + */ + public function getResponse() { + return $this->response; + } + + /** + * @param mixed $response + */ + public function setResponse($response) { + $this->response = $response; + } +} diff --git a/Civi/API/Events.php b/Civi/API/Events.php new file mode 100644 index 0000000000..36d9af45fa --- /dev/null +++ b/Civi/API/Events.php @@ -0,0 +1,83 @@ + PREPARE => RESPOND. + * If an exception arises in any stage, then the sequence is aborted and the EXCEPTION + * event is dispatched. + * + * Event subscribers which are concerned about the order of execution should assign + * a weight to their subscription (such as W_EARLY, W_MIDDLE, or W_LATE). + */ +class Events { + + /** + * Determine whether the API request is allowed for the current user. + * For successful execution, at least one listener must invoke $event->authorize(). + * + * @see AuthorizeEvent + */ + const AUTHORIZE = 'api.authorize'; + + /** + * Apply pre-execution logic + * + * @see PrepareEvent + */ + const PREPARE = 'api.prepare'; + + /** + * Apply post-execution logic + * + * @see RespondEvent + */ + const RESPOND = 'api.respond'; + + /** + * Handle any exceptions + * + * @see ExceptionEvent + */ + const EXCEPTION = 'api.exception'; + + /** + * Weight - Early + */ + const W_EARLY = 100; + + /** + * Weight - Middle + */ + const W_MIDDLE = 0; + + /** + * Weight - Late + */ + const W_LATE = -100; +} diff --git a/Civi/API/Kernel.php b/Civi/API/Kernel.php index 785e0ff264..8d982e1983 100644 --- a/Civi/API/Kernel.php +++ b/Civi/API/Kernel.php @@ -26,6 +26,12 @@ */ namespace Civi\API; +use Civi\API\Event\AuthorizeEvent; +use Civi\API\Event\PrepareEvent; +use Civi\API\Event\ExceptionEvent; +use Civi\API\Event\RespondEvent; + + /** * * @package Civi @@ -77,15 +83,22 @@ class Kernel { \CRM_Utils_Hook::apiWrappers($apiWrappers, $apiRequest); try { - require_once ('api/v3/utils.php'); - require_once 'api/Exception.php'; if (!is_array($params)) { throw new \API_Exception('Input variable `params` is not an array', 2000); } - _civicrm_api3_initialize(); + + $this->boot(); $errorScope = \CRM_Core_TemporaryErrorScope::useException(); + // look up function, file, is_generic $apiRequest += _civicrm_api_resolve($apiRequest); + + if (! $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent(NULL, $apiRequest))->isAuthorized()) { + throw new \API_Exception("Authorization failed"); + } + + $apiRequest = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent(NULL, $apiRequest))->getApiRequest(); + if (strtolower($action) == 'create' || strtolower($action) == 'delete' || strtolower($action) == 'submit') { $apiRequest['is_transactional'] = 1; $transaction = new \CRM_Core_Transaction(); @@ -136,18 +149,23 @@ class Kernel { if (\CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) { if ($result['is_error'] === 0) { + // FIXME dispatch return 1; } else { + // FIXME dispatch return 0; } } if (!empty($apiRequest['params']['format.only_id']) && isset($result['id'])) { + // FIXME dispatch return $result['id']; } + if (\CRM_Utils_Array::value('is_error', $result, 0) == 0) { _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']); } + if (function_exists('xdebug_time_index') && \CRM_Utils_Array::value('debug', $apiRequest['params']) // result would not be an array for getvalue @@ -158,6 +176,9 @@ class Kernel { $result['xdebug']['timeIndex'] = xdebug_time_index(); } + $responseEvent = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent(NULL, $apiRequest, $result)); + $result = $responseEvent->getResponse(); + return $result; } catch (PEAR_Exception $e) { if (\CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) { @@ -184,6 +205,7 @@ class Kernel { if (!empty($apiRequest['is_transactional'])) { $transaction->rollback(); } + $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest)); return $err; } catch (\API_Exception $e) { @@ -205,6 +227,7 @@ class Kernel { if (!empty($apiRequest['is_transactional'])) { $transaction->rollback(); } + $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest)); return $err; } catch (\Exception $e) { @@ -219,8 +242,15 @@ class Kernel { if (!empty($apiRequest['is_transactional'])) { $transaction->rollback(); } + $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest)); return $err; } } + + public function boot() { + require_once ('api/v3/utils.php'); + require_once 'api/Exception.php'; + _civicrm_api3_initialize(); + } } \ No newline at end of file diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index b2388f4c3a..98b69a813d 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -86,6 +86,10 @@ class Container { * @return \Civi\API\Kernel */ public function createApiKernel($dispatcher) { + $dispatcher->addListener(\Civi\API\Events::AUTHORIZE, function($event) { + // dummy placeholder + $event->authorize(); + }); $kernel = new \Civi\API\Kernel($dispatcher, array()); return $kernel; } -- 2.25.1