Merge pull request #16406 from totten/master-menu-warn
[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\ActionUtil;
27 use Civi\Api4\Utils\ReflectionUtils;
28
29 /**
30 * Get actions for an entity with a list of accepted params
31 */
32 class GetActions extends BasicGetAction {
33
34 private $_actions = [];
35
36 private $_actionsToGet;
37
38 protected function getRecords() {
39 $this->_actionsToGet = $this->_itemsToGet('name');
40
41 $entityReflection = new \ReflectionClass('\Civi\Api4\\' . $this->_entityName);
42 foreach ($entityReflection->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC) as $method) {
43 $actionName = $method->getName();
44 if ($actionName != 'permissions' && $actionName[0] != '_') {
45 $this->loadAction($actionName, $method);
46 }
47 }
48 if (!$this->_actionsToGet || count($this->_actionsToGet) > count($this->_actions)) {
49 // Search for entity-specific actions in extensions
50 foreach (\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles() as $ext) {
51 $dir = \CRM_Utils_File::addTrailingSlash(dirname($ext['filePath']));
52 $this->scanDir($dir . 'Civi/Api4/Action/' . $this->_entityName);
53 }
54 // Search for entity-specific actions in core
55 $this->scanDir(\CRM_Utils_File::addTrailingSlash(__DIR__) . $this->_entityName);
56 }
57 ksort($this->_actions);
58 return $this->_actions;
59 }
60
61 /**
62 * @param $dir
63 */
64 private function scanDir($dir) {
65 if (is_dir($dir)) {
66 foreach (glob("$dir/*.php") as $file) {
67 $matches = [];
68 preg_match('/(\w*).php/', $file, $matches);
69 $actionName = array_pop($matches);
70 $actionClass = new \ReflectionClass('\\Civi\\Api4\\Action\\' . $this->_entityName . '\\' . $actionName);
71 if ($actionClass->isInstantiable() && $actionClass->isSubclassOf('\\Civi\\Api4\\Generic\\AbstractAction')) {
72 $this->loadAction(lcfirst($actionName));
73 }
74 }
75 }
76 }
77
78 /**
79 * @param $actionName
80 * @param \ReflectionMethod $method
81 */
82 private function loadAction($actionName, $method = NULL) {
83 try {
84 if (!isset($this->_actions[$actionName]) && (!$this->_actionsToGet || in_array($actionName, $this->_actionsToGet))) {
85 $action = ActionUtil::getAction($this->getEntityName(), $actionName);
86 if (is_object($action)) {
87 $this->_actions[$actionName] = ['name' => $actionName];
88 if ($this->_isFieldSelected('description', 'comment', 'see')) {
89 // Docblock from action class
90 $actionDocs = ReflectionUtils::getCodeDocs($action->reflect());
91 unset($actionDocs['method']);
92 // Docblock from action factory function in entity class. This takes precedence since most action classes are generic.
93 if ($method) {
94 $methodDocs = ReflectionUtils::getCodeDocs($method, 'Method');
95 $actionDocs = $methodDocs + $actionDocs;
96 }
97 $this->_actions[$actionName] += $actionDocs;
98 }
99 if ($this->_isFieldSelected('params')) {
100 $this->_actions[$actionName]['params'] = $action->getParamInfo();
101 // Language param is only relevant on multilingual sites
102 $languageLimit = (array) \Civi::settings()->get('languageLimit');
103 if (count($languageLimit) < 2) {
104 unset($this->_actions[$actionName]['params']['language']);
105 }
106 elseif (isset($this->_actions[$actionName]['params']['language'])) {
107 $this->_actions[$actionName]['params']['language']['options'] = array_keys($languageLimit);
108 }
109 }
110 }
111 }
112 }
113 catch (NotImplementedException $e) {
114 }
115 }
116
117 public function fields() {
118 return [
119 [
120 'name' => 'name',
121 'description' => 'Action name',
122 ],
123 [
124 'name' => 'description',
125 'description' => 'Description from docblock',
126 ],
127 [
128 'name' => 'comment',
129 'description' => 'Comments from docblock',
130 ],
131 [
132 'name' => 'see',
133 'data_type' => 'Array',
134 'description' => 'Any @see annotations from docblock',
135 ],
136 [
137 'name' => 'params',
138 'description' => 'List of all accepted parameters',
139 'data_type' => 'Array',
140 ],
141 ];
142 }
143
144 }