use Civi\API\Event\ExceptionEvent;
use Civi\API\Event\ResolveEvent;
use Civi\API\Event\RespondEvent;
+use Civi\API\Provider\ProviderInterface;
/**
*
protected $dispatcher;
/**
- * @var array<APIProviderInterface>
+ * @var array<ProviderInterface>
*/
protected $apiProviders;
$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));
_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
*/
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")
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',
);
}
}