Api4 - Use explicit adder functions rather than magicMethod
[civicrm-core.git] / Civi / Api4 / Generic / BasicGetFieldsAction.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\Generic;
23
24 use Civi\API\Exception\NotImplementedException;
25 use Civi\Api4\Utils\ActionUtil;
26
27 /**
28 * Get fields for an entity.
29 *
30 * @method $this setLoadOptions(bool $value)
31 * @method bool getLoadOptions()
32 * @method $this setAction(string $value)
33 * @method $this setValues(array $values)
34 * @method array getValues()
35 */
36 class BasicGetFieldsAction extends BasicGetAction {
37
38 /**
39 * Fetch option lists for fields?
40 *
41 * @var bool
42 */
43 protected $loadOptions = FALSE;
44
45 /**
46 * Fields will be returned appropriate to the specified action (get, create, delete, etc.)
47 *
48 * @var string
49 */
50 protected $action = 'get';
51
52 /**
53 * Fields will be returned appropriate to the specified values (e.g. ['contact_type' => 'Individual'])
54 *
55 * @var array
56 */
57 protected $values = [];
58
59 /**
60 * To implement getFields for your own entity:
61 *
62 * 1. From your entity class add a static getFields method.
63 * 2. That method should construct and return this class.
64 * 3. The 3rd argument passed to this constructor should be a function that returns an
65 * array of fields for your entity's CRUD actions.
66 * 4. For non-crud actions that need a different set of fields, you can override the
67 * list from step 3 on a per-action basis by defining a fields() method in that action.
68 * See for example BasicGetFieldsAction::fields() or GetActions::fields().
69 *
70 * @param Result $result
71 * @throws \Civi\API\Exception\NotImplementedException
72 */
73 public function _run(Result $result) {
74 try {
75 $actionClass = ActionUtil::getAction($this->getEntityName(), $this->getAction());
76 }
77 catch (NotImplementedException $e) {
78 }
79 if (isset($actionClass) && method_exists($actionClass, 'fields')) {
80 $values = $actionClass->fields();
81 }
82 else {
83 $values = $this->getRecords();
84 }
85 $this->padResults($values);
86 $result->exchangeArray($this->queryArray($values));
87 }
88
89 /**
90 * Ensure every result contains, at minimum, the array keys as defined in $this->fields.
91 *
92 * Attempt to set some sensible defaults for some fields.
93 *
94 * In most cases it's not necessary to override this function, even if your entity is really weird.
95 * Instead just override $this->fields and thes function will respect that.
96 *
97 * @param array $values
98 */
99 protected function padResults(&$values) {
100 $fields = array_column($this->fields(), 'name');
101 foreach ($values as &$field) {
102 $defaults = array_intersect_key([
103 'title' => empty($field['name']) ? NULL : ucwords(str_replace('_', ' ', $field['name'])),
104 'entity' => $this->getEntityName(),
105 'required' => FALSE,
106 'options' => !empty($field['pseudoconstant']),
107 'data_type' => \CRM_Utils_Array::value('type', $field, 'String'),
108 ], array_flip($fields));
109 $field += $defaults;
110 if (!$this->loadOptions && isset($defaults['options'])) {
111 $field['options'] = (bool) $field['options'];
112 }
113 $field += array_fill_keys($fields, NULL);
114 }
115 }
116
117 /**
118 * @return string
119 */
120 public function getAction() {
121 // For actions that build on top of other actions, return fields for the simpler action
122 $sub = [
123 'save' => 'create',
124 'replace' => 'create',
125 ];
126 return $sub[$this->action] ?? $this->action;
127 }
128
129 /**
130 * Add an item to the values array
131 * @param string $fieldName
132 * @param mixed $value
133 * @return $this
134 */
135 public function addValue(string $fieldName, $value) {
136 $this->values[$fieldName] = $value;
137 return $this;
138 }
139
140 public function fields() {
141 return [
142 [
143 'name' => 'name',
144 'data_type' => 'String',
145 ],
146 [
147 'name' => 'title',
148 'data_type' => 'String',
149 ],
150 [
151 'name' => 'description',
152 'data_type' => 'String',
153 ],
154 [
155 'name' => 'default_value',
156 'data_type' => 'String',
157 ],
158 [
159 'name' => 'required',
160 'data_type' => 'Boolean',
161 ],
162 [
163 'name' => 'required_if',
164 'data_type' => 'String',
165 ],
166 [
167 'name' => 'options',
168 'data_type' => 'Array',
169 ],
170 [
171 'name' => 'data_type',
172 'data_type' => 'String',
173 ],
174 [
175 'name' => 'input_type',
176 'data_type' => 'String',
177 ],
178 [
179 'name' => 'input_attrs',
180 'data_type' => 'Array',
181 ],
182 [
183 'name' => 'fk_entity',
184 'data_type' => 'String',
185 ],
186 [
187 'name' => 'serialize',
188 'data_type' => 'Integer',
189 ],
190 [
191 'name' => 'entity',
192 'data_type' => 'String',
193 ],
194 ];
195 }
196
197 }