CRM-14370 - API Kernel - Move dispatch into helpers
authorTim Otten <totten@civicrm.org>
Fri, 28 Mar 2014 04:45:16 +0000 (21:45 -0700)
committerTim Otten <totten@civicrm.org>
Sun, 6 Apr 2014 04:17:43 +0000 (21:17 -0700)
Also: Use constants for error codes

Civi/API/Kernel.php
api/Exception.php

index 69f96b8da960d9788462a0f02cd56c1d8e0dd761..e5c098f9bec93b115f2d464e0e41e9d9560cd98a 100644 (file)
@@ -31,6 +31,7 @@ use Civi\API\Event\PrepareEvent;
 use Civi\API\Event\ExceptionEvent;
 use Civi\API\Event\ResolveEvent;
 use Civi\API\Event\RespondEvent;
+use Civi\API\Provider\ProviderInterface;
 
 /**
  *
@@ -46,7 +47,7 @@ class Kernel {
   protected $dispatcher;
 
   /**
-   * @var array<APIProviderInterface>
+   * @var array<ProviderInterface>
    */
   protected $apiProviders;
 
@@ -84,26 +85,17 @@ class Kernel {
       $this->boot();
       $errorScope = \CRM_Core_TemporaryErrorScope::useException();
 
-      $resolveEvent = $this->dispatcher->dispatch(Events::RESOLVE, new ResolveEvent($apiRequest));
-      $apiRequest = $resolveEvent->getApiRequest();
-      $apiProvider = $resolveEvent->getApiProvider();
-      if (!$apiProvider) {
-        throw new \API_Exception("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
-      }
-
-      if (! $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent($apiProvider, $apiRequest))->isAuthorized()) {
-        throw new \API_Exception("Authorization failed", 'unauthorized');
-      }
-
-      $apiRequest = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent($apiProvider, $apiRequest))->getApiRequest();
+      list($apiProvider, $apiRequest) = $this->resolve($apiRequest);
+      $this->authorize($apiProvider, $apiRequest);
+      $apiRequest = $this->prepare($apiProvider, $apiRequest);
       $result = $apiProvider->invoke($apiRequest);
 
       if (\CRM_Utils_Array::value('is_error', $result, 0) == 0) {
         _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']);
       }
 
-      $responseEvent = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent($apiProvider, $apiRequest, $result));
-      return $this->formatResult($apiRequest, $responseEvent->getResponse());
+      $apiResponse = $this->respond($apiProvider, $apiRequest, $result);
+      return $this->formatResult($apiRequest, $apiResponse);
     }
     catch (\Exception $e) {
       $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, $apiProvider, $apiRequest));
@@ -231,6 +223,61 @@ class Kernel {
     _civicrm_api3_initialize();
   }
 
+  /**
+   * Determine which, if any, service will execute the API request.
+   *
+   * @param $apiRequest
+   * @return array
+   * @throws \API_Exception
+   */
+  public function resolve($apiRequest) {
+    $resolveEvent = $this->dispatcher->dispatch(Events::RESOLVE, new ResolveEvent($apiRequest));
+    $apiRequest = $resolveEvent->getApiRequest();
+    if (!$resolveEvent->getApiProvider()) {
+      throw new \API_Exception("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)", \API_Exception::NOT_IMPLEMENTED);
+    }
+    return array($resolveEvent->getApiProvider(), $apiRequest);
+  }
+
+  /**
+   * Determine if the API request is allowed (under current policy)
+   *
+   * @param ProviderInterface $apiProvider
+   * @param array $apiRequest
+   * @throws \API_Exception
+   */
+  public function authorize($apiProvider, $apiRequest) {
+    $event = $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent($apiProvider, $apiRequest));
+    if (!$event->isAuthorized()) {
+      throw new \API_Exception("Authorization failed", \API_Exception::UNAUTHORIZED);
+    }
+  }
+
+  /**
+   * Allow third-party code to manipulate the API request before execution.
+   *
+   * @param ProviderInterface $apiProvider
+   * @param array $apiRequest
+   * @return mixed
+   */
+  public function prepare($apiProvider, $apiRequest) {
+    $event = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent($apiProvider, $apiRequest));
+    return $event->getApiRequest();
+  }
+
+  /**
+   * Allow third-party code to manipulate the API response after execution.
+   *
+   * @param ProviderInterface $apiProvider
+   * @param array $apiRequest
+   * @param array $result
+   * @return mixed
+   */
+  public function respond($apiProvider, $apiRequest, $result) {
+    $event = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent($apiProvider, $apiRequest, $result));
+    return $event->getResponse();
+  }
+
   /**
    * @param \Exception $e
    * @param array $apiRequest
index 254ab3752d8c5eb0ec81ee47113ce5f6b66b5582..48d89e7572e38097ac56c65b6ac64a6ffee3ddbc 100644 (file)
@@ -21,6 +21,9 @@
  */
 class API_Exception extends Exception
 {
+  const UNAUTHORIZED = 'unauthorized';
+  const NOT_IMPLEMENTED = 'not-found';
+
   private $extraParams = array();
   public function __construct($message, $error_code = 0, $extraParams = array(),Exception $previous = null) {
     if (is_numeric ($error_code)) // using int for error code "old way")
@@ -44,7 +47,9 @@ class API_Exception extends Exception
     return array(
         2000 => '$params was not an array',
         2001 => 'Invalid Value for Date field',
-        2100 => 'String value is longer than permitted length'
+        2100 => 'String value is longer than permitted length',
+        self::UNAUTHORIZED => 'Unauthorized',
+        self::NOT_IMPLEMENTED => 'Entity or method is not implemented',
         );
   }
 }