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