3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
12 namespace Civi\Api4\Provider
;
14 use Civi\API\Event\ResolveEvent
;
15 use Civi\API\Provider\ProviderInterface
;
16 use Civi\Api4\Generic\AbstractAction
;
18 use Civi\Api4\Utils\ReflectionUtils
;
19 use Symfony\Component\EventDispatcher\EventSubscriberInterface
;
22 * Accept $apiRequests based on \Civi\API\Action
24 class ActionObjectProvider
implements EventSubscriberInterface
, ProviderInterface
{
29 public static function getSubscribedEvents() {
30 // Using a high priority allows adhoc implementations
31 // to override standard implementations -- which is
32 // handy for testing/mocking.
34 'civi.api.resolve' => [
35 ['onApiResolve', Events
::W_EARLY
],
41 * @param \Civi\API\Event\ResolveEvent $event
42 * API resolution event.
44 public function onApiResolve(ResolveEvent
$event) {
45 $apiRequest = $event->getApiRequest();
46 if ($apiRequest instanceof AbstractAction
) {
47 $event->setApiRequest($apiRequest);
48 $event->setApiProvider($this);
49 $event->stopPropagation();
56 * @param \Civi\Api4\Generic\AbstractAction $action
58 * @return \Civi\Api4\Generic\Result
60 public function invoke($action) {
61 // Load result class based on @return annotation in the execute() method.
62 $reflection = new \
ReflectionClass($action);
63 $doc = ReflectionUtils
::getCodeDocs($reflection->getMethod('execute'), 'Method');
64 $resultClass = $doc['return'][0] ??
'\\Civi\\Api4\\Generic\\Result';
65 $result = new $resultClass();
66 $result->action
= $action->getActionName();
67 $result->entity
= $action->getEntityName();
68 $action->_run($result);
69 $this->handleChains($action, $result);
74 * Run each chained action once per row
76 * @param \Civi\Api4\Generic\AbstractAction $action
77 * @param \Civi\Api4\Generic\Result $result
79 protected function handleChains($action, $result) {
80 foreach ($action->getChain() as $name => $request) {
81 $request +
= [NULL, NULL, [], NULL];
82 $request[2]['checkPermissions'] = $action->getCheckPermissions();
83 foreach ($result as &$row) {
84 $row[$name] = $this->runChain($request, $row);
90 * Run a chained action
94 * @return array|\Civi\Api4\Generic\Result|null
95 * @throws \API_Exception
97 protected function runChain($request, $row) {
98 list($entity, $action, $params, $index) = $request;
99 // Swap out variables in $entity, $action & $params
100 $this->resolveChainLinks($entity, $row);
101 $this->resolveChainLinks($action, $row);
102 $this->resolveChainLinks($params, $row);
103 return (array) civicrm_api4($entity, $action, $params, $index);
107 * Swap out variable names
110 * @param array $result
112 protected function resolveChainLinks(&$val, $result) {
113 if (is_array($val)) {
114 foreach ($val as &$v) {
115 $this->resolveChainLinks($v, $result);
118 elseif (is_string($val) && strlen($val) > 1 && substr($val, 0, 1) === '$') {
119 $val = \CRM_Utils_Array
::pathGet($result, explode('.', substr($val, 1)));
125 * @param int $version
128 public function getEntityNames($version) {
135 * @param int $version
136 * @param string $entity
139 public function getActionNames($version, $entity) {
140 /** FIXME Civi\API\V4\Action\GetActions */