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