Commit | Line | Data |
---|---|---|
19b53e5b C |
1 | <?php |
2 | ||
380f3545 TO |
3 | /* |
4 | +--------------------------------------------------------------------+ | |
41498ac5 | 5 | | Copyright CiviCRM LLC. All rights reserved. | |
380f3545 | 6 | | | |
41498ac5 TO |
7 | | This work is published under the GNU AGPLv3 license with some | |
8 | | permitted exceptions and without any warranty. For full license | | |
9 | | and copyright information, see https://civicrm.org/licensing | | |
380f3545 TO |
10 | +--------------------------------------------------------------------+ |
11 | */ | |
12 | ||
19b53e5b C |
13 | namespace Civi\Api4\Action; |
14 | ||
15 | use Civi\API\Exception\NotImplementedException; | |
16 | use Civi\Api4\Generic\BasicGetAction; | |
26258982 | 17 | use Civi\Api4\Utils\CoreUtil; |
19b53e5b C |
18 | use Civi\Api4\Utils\ReflectionUtils; |
19 | ||
20 | /** | |
fc95d9a5 CW |
21 | * Get all API actions for the $ENTITY entity. |
22 | * | |
23 | * Includes a list of accepted parameters for each action, descriptions and other documentation. | |
19b53e5b C |
24 | */ |
25 | class GetActions extends BasicGetAction { | |
26 | ||
27 | private $_actions = []; | |
28 | ||
29 | private $_actionsToGet; | |
30 | ||
31 | protected function getRecords() { | |
32 | $this->_actionsToGet = $this->_itemsToGet('name'); | |
33 | ||
26258982 CW |
34 | $className = CoreUtil::getApiClass($this->_entityName); |
35 | $entityReflection = new \ReflectionClass($className); | |
19b53e5b C |
36 | foreach ($entityReflection->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC) as $method) { |
37 | $actionName = $method->getName(); | |
449c4e6b | 38 | if ($actionName != 'permissions' && $actionName != 'getInfo' && $actionName[0] != '_') { |
e15f9453 | 39 | $this->loadAction($actionName, $method); |
19b53e5b C |
40 | } |
41 | } | |
42 | if (!$this->_actionsToGet || count($this->_actionsToGet) > count($this->_actions)) { | |
23c2d07c | 43 | // Search for entity-specific actions in extensions |
26258982 | 44 | $nameSpace = str_replace('Civi\Api4\\', 'Civi\Api4\Action\\', $className); |
19b53e5b C |
45 | foreach (\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles() as $ext) { |
46 | $dir = \CRM_Utils_File::addTrailingSlash(dirname($ext['filePath'])); | |
26258982 | 47 | $this->scanDir($dir, $nameSpace); |
19b53e5b | 48 | } |
23c2d07c | 49 | // Search for entity-specific actions in core |
26258982 CW |
50 | global $civicrm_root; |
51 | $this->scanDir(\CRM_Utils_File::addTrailingSlash($civicrm_root), $nameSpace); | |
19b53e5b C |
52 | } |
53 | ksort($this->_actions); | |
54 | return $this->_actions; | |
55 | } | |
56 | ||
57 | /** | |
26258982 CW |
58 | * @param string $dir |
59 | * @param string $nameSpace | |
19b53e5b | 60 | */ |
26258982 CW |
61 | private function scanDir($dir, $nameSpace) { |
62 | $dir .= str_replace('\\', '/', $nameSpace); | |
19b53e5b C |
63 | if (is_dir($dir)) { |
64 | foreach (glob("$dir/*.php") as $file) { | |
26258982 CW |
65 | $actionName = basename($file, '.php'); |
66 | $actionClass = new \ReflectionClass($nameSpace . '\\' . $actionName); | |
a62d97f3 | 67 | if ($actionClass->isInstantiable() && $actionClass->isSubclassOf('\Civi\Api4\Generic\AbstractAction')) { |
19b53e5b C |
68 | $this->loadAction(lcfirst($actionName)); |
69 | } | |
70 | } | |
71 | } | |
72 | } | |
73 | ||
74 | /** | |
75 | * @param $actionName | |
e15f9453 | 76 | * @param \ReflectionMethod $method |
19b53e5b | 77 | */ |
e15f9453 | 78 | private function loadAction($actionName, $method = NULL) { |
19b53e5b C |
79 | try { |
80 | if (!isset($this->_actions[$actionName]) && (!$this->_actionsToGet || in_array($actionName, $this->_actionsToGet))) { | |
3a8dc228 | 81 | $action = \Civi\API\Request::create($this->getEntityName(), $actionName, ['version' => 4]); |
7e67fdb7 | 82 | if (is_object($action) && (!$this->checkPermissions || $action->isAuthorized())) { |
19b53e5b | 83 | $this->_actions[$actionName] = ['name' => $actionName]; |
e15f9453 | 84 | if ($this->_isFieldSelected('description', 'comment', 'see')) { |
e3c6d5ff | 85 | $vars = ['entity' => $this->getEntityName(), 'action' => $actionName]; |
e15f9453 | 86 | // Docblock from action class |
fc95d9a5 | 87 | $actionDocs = ReflectionUtils::getCodeDocs($action->reflect(), NULL, $vars); |
e15f9453 CW |
88 | unset($actionDocs['method']); |
89 | // Docblock from action factory function in entity class. This takes precedence since most action classes are generic. | |
90 | if ($method) { | |
fc95d9a5 CW |
91 | $methodDocs = ReflectionUtils::getCodeDocs($method, 'Method', $vars); |
92 | // Allow method doc to inherit class doc | |
93 | if (strpos($method->getDocComment(), '@inheritDoc') !== FALSE && !empty($methodDocs['comment']) && !empty($actionDocs['comment'])) { | |
94 | $methodDocs['comment'] .= "\n\n" . $actionDocs['comment']; | |
95 | } | |
96 | $actionDocs = array_filter($methodDocs) + $actionDocs; | |
e15f9453 CW |
97 | } |
98 | $this->_actions[$actionName] += $actionDocs; | |
19b53e5b C |
99 | } |
100 | if ($this->_isFieldSelected('params')) { | |
101 | $this->_actions[$actionName]['params'] = $action->getParamInfo(); | |
102 | // Language param is only relevant on multilingual sites | |
103 | $languageLimit = (array) \Civi::settings()->get('languageLimit'); | |
104 | if (count($languageLimit) < 2) { | |
105 | unset($this->_actions[$actionName]['params']['language']); | |
106 | } | |
107 | elseif (isset($this->_actions[$actionName]['params']['language'])) { | |
108 | $this->_actions[$actionName]['params']['language']['options'] = array_keys($languageLimit); | |
109 | } | |
110 | } | |
111 | } | |
112 | } | |
113 | } | |
114 | catch (NotImplementedException $e) { | |
115 | } | |
116 | } | |
117 | ||
118 | public function fields() { | |
119 | return [ | |
120 | [ | |
121 | 'name' => 'name', | |
e15f9453 | 122 | 'description' => 'Action name', |
19b53e5b C |
123 | ], |
124 | [ | |
125 | 'name' => 'description', | |
e15f9453 | 126 | 'description' => 'Description from docblock', |
19b53e5b C |
127 | ], |
128 | [ | |
129 | 'name' => 'comment', | |
e15f9453 CW |
130 | 'description' => 'Comments from docblock', |
131 | ], | |
132 | [ | |
133 | 'name' => 'see', | |
134 | 'data_type' => 'Array', | |
135 | 'description' => 'Any @see annotations from docblock', | |
19b53e5b C |
136 | ], |
137 | [ | |
138 | 'name' => 'params', | |
e15f9453 | 139 | 'description' => 'List of all accepted parameters', |
19b53e5b C |
140 | 'data_type' => 'Array', |
141 | ], | |
142 | ]; | |
143 | } | |
144 | ||
145 | } |