<?php
/*
+--------------------------------------------------------------------+
- | CiviCRM version 4.4 |
+ | CiviCRM version 4.6 |
+--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2013 |
+ | Copyright CiviCRM LLC (c) 2004-2015 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
-*/
+ */
namespace Civi\API;
use Civi\API\Event\AuthorizeEvent;
use Civi\API\Provider\ProviderInterface;
/**
- *
* @package Civi
- * @copyright CiviCRM LLC (c) 2004-2013
+ * @copyright CiviCRM LLC (c) 2004-2015
*/
-
class Kernel {
/**
*/
protected $apiProviders;
- function __construct($dispatcher, $apiProviders = array()) {
+ /**
+ * @param \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
+ * The event dispatcher which receives kernel events.
+ * @param array $apiProviders
+ * Array of ProviderInterface.
+ */
+ public function __construct($dispatcher, $apiProviders = array()) {
$this->apiProviders = $apiProviders;
$this->dispatcher = $dispatcher;
}
/**
* @param string $entity
- * type of entities to deal with
+ * Type of entities to deal with.
* @param string $action
- * create, get, delete or some special action name.
+ * Create, get, delete or some special action name.
* @param array $params
- * array to be passed to function
- * @param null $extra
+ * Array to be passed to API function.
+ * @param mixed $extra
+ * Who knows.
*
* @return array|int
*/
- public function run($entity, $action, $params, $extra) {
+ public function run($entity, $action, $params, $extra = NULL) {
/**
* @var $apiProvider \Civi\API\Provider\ProviderInterface|NULL
*/
$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']);
- }
-
$apiResponse = $this->respond($apiProvider, $apiRequest, $result);
return $this->formatResult($apiRequest, $apiResponse);
}
catch (\Exception $e) {
- $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, $apiProvider, $apiRequest));
+ $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, $apiProvider, $apiRequest, $this));
if ($e instanceof \PEAR_Exception) {
$err = $this->formatPearException($e, $apiRequest);
- } elseif ($e instanceof \API_Exception) {
+ }
+ elseif ($e instanceof \API_Exception) {
$err = $this->formatApiException($e, $apiRequest);
- } else {
+ }
+ else {
$err = $this->formatException($e, $apiRequest);
}
}
}
+ /**
+ * Determine if a hypothetical API call would be authorized.
+ *
+ * @param string $entity
+ * Type of entities to deal with.
+ * @param string $action
+ * Create, get, delete or some special action name.
+ * @param array $params
+ * Array to be passed to function.
+ * @param mixed $extra
+ * Who knows.
+ * @return bool
+ * TRUE if authorization would succeed.
+ * @throws \Exception
+ */
+ public function runAuthorize($entity, $action, $params, $extra = NULL) {
+ $apiProvider = NULL;
+ $apiRequest = Request::create($entity, $action, $params, $extra);
+
+ try {
+ $this->boot();
+ list($apiProvider, $apiRequest) = $this->resolve($apiRequest);
+ $this->authorize($apiProvider, $apiRequest);
+ return TRUE;
+ }
+ catch (\Civi\API\Exception\UnauthorizedException $e) {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Bootstrap - Load basic dependencies.
+ */
public function boot() {
- require_once ('api/v3/utils.php');
+ require_once 'api/v3/utils.php';
require_once 'api/Exception.php';
_civicrm_api3_initialize();
}
/**
* Determine which, if any, service will execute the API request.
*
- * @param $apiRequest
+ * @param array $apiRequest
+ * The full description of the API request.
+ * @throws Exception\NotImplementedException
* @return array
- * @throws \API_Exception
+ * Array(0 => ProviderInterface, 1 => array).
*/
public function resolve($apiRequest) {
- $resolveEvent = $this->dispatcher->dispatch(Events::RESOLVE, new ResolveEvent($apiRequest));
+ /** @var ResolveEvent $resolveEvent */
+ $resolveEvent = $this->dispatcher->dispatch(Events::RESOLVE, new ResolveEvent($apiRequest, $this));
$apiRequest = $resolveEvent->getApiRequest();
if (!$resolveEvent->getApiProvider()) {
throw new \Civi\API\Exception\NotImplementedException("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
* Determine if the API request is allowed (under current policy)
*
* @param ProviderInterface $apiProvider
+ * The API provider responsible for executing the request.
* @param array $apiRequest
- * @throws \API_Exception
+ * The full description of the API request.
+ * @throws Exception\UnauthorizedException
*/
public function authorize($apiProvider, $apiRequest) {
- $event = $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent($apiProvider, $apiRequest));
+ /** @var AuthorizeEvent $event */
+ $event = $this->dispatcher->dispatch(Events::AUTHORIZE, new AuthorizeEvent($apiProvider, $apiRequest, $this));
if (!$event->isAuthorized()) {
throw new \Civi\API\Exception\UnauthorizedException("Authorization failed");
}
* Allow third-party code to manipulate the API request before execution.
*
* @param ProviderInterface $apiProvider
+ * The API provider responsible for executing the request.
* @param array $apiRequest
+ * The full description of the API request.
* @return mixed
*/
public function prepare($apiProvider, $apiRequest) {
- $event = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent($apiProvider, $apiRequest));
+ /** @var PrepareEvent $event */
+ $event = $this->dispatcher->dispatch(Events::PREPARE, new PrepareEvent($apiProvider, $apiRequest, $this));
return $event->getApiRequest();
}
* Allow third-party code to manipulate the API response after execution.
*
* @param ProviderInterface $apiProvider
+ * The API provider responsible for executing the request.
* @param array $apiRequest
+ * The full description of the API request.
* @param array $result
+ * The response to return to the client.
* @return mixed
*/
public function respond($apiProvider, $apiRequest, $result) {
- $event = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent($apiProvider, $apiRequest, $result));
+ /** @var RespondEvent $event */
+ $event = $this->dispatcher->dispatch(Events::RESPOND, new RespondEvent($apiProvider, $apiRequest, $result, $this));
return $event->getResponse();
}
/**
* @param int $version
- * @return array<string>
+ * API version.
+ * @return array
+ * Array<string>.
*/
public function getEntityNames($version) {
// Question: Would it better to eliminate $this->apiProviders and just use $this->dispatcher?
$entityNames = array();
foreach ($this->getApiProviders() as $provider) {
+ /** @var ProviderInterface $provider */
$entityNames = array_merge($entityNames, $provider->getEntityNames($version));
}
$entityNames = array_unique($entityNames);
/**
* @param int $version
+ * API version.
* @param string $entity
- * @return array<string>
+ * API entity.
+ * @return array
+ * Array<string>
*/
public function getActionNames($version, $entity) {
// Question: Would it better to eliminate $this->apiProviders and just use $this->dispatcher?
$actionNames = array();
foreach ($this->getApiProviders() as $provider) {
+ /** @var ProviderInterface $provider */
$actionNames = array_merge($actionNames, $provider->getActionNames($version, $entity));
}
$actionNames = array_unique($actionNames);
/**
* @param \Exception $e
+ * An unhandled exception.
* @param array $apiRequest
- * @return array (API response)
+ * The full description of the API request.
+ * @return array
+ * API response.
*/
public function formatException($e, $apiRequest) {
$data = array();
/**
* @param \API_Exception $e
+ * An unhandled exception.
* @param array $apiRequest
- * @return array (API response)
+ * The full description of the API request.
+ * @return array
+ * (API response)
*/
public function formatApiException($e, $apiRequest) {
$data = $e->getExtraParams();
/**
* @param \PEAR_Exception $e
+ * An unhandled exception.
* @param array $apiRequest
- * @return array (API response)
+ * The full description of the API request.
+ * @return array
+ * API response.
*/
public function formatPearException($e, $apiRequest) {
$data = array();
}
/**
- *
- * @param <type> $data
+ * @param string $msg
+ * Descriptive error message.
* @param array $data
- * @param object $apiRequest DAO / BAO object to be freed here
+ * Error data.
+ * @param array $apiRequest
+ * The full description of the API request.
+ * @param mixed $code
+ * Doesn't appear to be used.
*
- * @throws API_Exception
- * @return array <type>
+ * @throws \API_Exception
+ * @return array
+ * Array<type>.
*/
- function createError($msg, $data, $apiRequest, $code = NULL) {
+ public function createError($msg, $data, $apiRequest, $code = NULL) {
// FIXME what to do with $code?
if ($msg == 'DB Error: constraint violation' || substr($msg, 0, 9) == 'DB Error:' || $msg == 'DB Error: already exists') {
try {
$fields = _civicrm_api3_api_getfields($apiRequest);
_civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $fields, TRUE);
- } catch (Exception $e) {
+ }
+ catch (\Exception $e) {
$msg = $e->getMessage();
}
}
}
/**
+ * @param array $apiRequest
+ * The full description of the API request.
+ * @param array $result
+ * The response to return to the client.
* @return mixed
*/
public function formatResult($apiRequest, $result) {
/**
* @param array $apiProviders
+ * Array<ProviderInterface>.
+ * @return Kernel
*/
public function setApiProviders($apiProviders) {
$this->apiProviders = $apiProviders;
+ return $this;
+ }
+
+ /**
+ * @param ProviderInterface $apiProvider
+ * The API provider responsible for executing the request.
+ * @return Kernel
+ */
+ public function registerApiProvider($apiProvider) {
+ $this->apiProviders[] = $apiProvider;
+ if ($apiProvider instanceof \Symfony\Component\EventDispatcher\EventSubscriberInterface) {
+ $this->getDispatcher()->addSubscriber($apiProvider);
+ }
+ return $this;
}
/**
/**
* @param \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
+ * The event dispatcher which receives kernel events.
+ * @return Kernel
*/
public function setDispatcher($dispatcher) {
$this->dispatcher = $dispatcher;
+ return $this;
}
-}
\ No newline at end of file
+
+}