Merge pull request #23348 from colemanw/getFieldsSuffixes
[civicrm-core.git] / Civi / Api4 / Generic / DAOGetFieldsAction.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 namespace Civi\Api4\Generic;
14
15 use Civi\Api4\Utils\CoreUtil;
16 use Civi\Api4\Utils\FormattingUtil;
17
18 /**
19 * @inheritDoc
20 * @method bool getIncludeCustom()
21 */
22 class DAOGetFieldsAction extends BasicGetFieldsAction {
23
24 /**
25 * Get fields for a DAO-based entity.
26 *
27 * @return array
28 */
29 protected function getRecords() {
30 $fieldsToGet = $this->_itemsToGet('name');
31 $typesToGet = $this->_itemsToGet('type');
32 /** @var \Civi\Api4\Service\Spec\SpecGatherer $gatherer */
33 $gatherer = \Civi::container()->get('spec_gatherer');
34 $includeCustom = TRUE;
35 if ($typesToGet) {
36 $includeCustom = in_array('Custom', $typesToGet, TRUE);
37 }
38 elseif ($fieldsToGet) {
39 // Any fields name with a dot in it is either custom or an implicit join
40 $includeCustom = strpos(implode('', $fieldsToGet), '.') !== FALSE;
41 }
42 $this->formatValues();
43 $spec = $gatherer->getSpec($this->getEntityName(), $this->getAction(), $includeCustom, $this->values);
44 $fields = $this->specToArray($spec->getFields($fieldsToGet));
45 foreach ($fieldsToGet ?? [] as $fieldName) {
46 if (empty($fields[$fieldName]) && strpos($fieldName, '.') !== FALSE) {
47 $fkField = $this->getFkFieldSpec($fieldName, $fields);
48 if ($fkField) {
49 $fkField['name'] = $fieldName;
50 $fields[] = $fkField;
51 }
52 }
53 }
54 return $fields;
55 }
56
57 /**
58 * @param \Civi\Api4\Service\Spec\FieldSpec[] $fields
59 *
60 * @return array
61 */
62 protected function specToArray($fields) {
63 $fieldArray = [];
64
65 foreach ($fields as $field) {
66 if ($this->loadOptions) {
67 $field->getOptions($this->values, $this->loadOptions, $this->checkPermissions);
68 }
69 $fieldArray[$field->getName()] = $field->toArray();
70 }
71
72 return $fieldArray;
73 }
74
75 /**
76 * @param string $fieldName
77 * @param array $fields
78 * @return array|null
79 * @throws \API_Exception
80 */
81 private function getFkFieldSpec($fieldName, $fields) {
82 $fieldPath = explode('.', $fieldName);
83 // Search for the first segment alone plus the first and second
84 // No field in the schema contains more than one dot in its name.
85 $searchPaths = [$fieldPath[0], $fieldPath[0] . '.' . $fieldPath[1]];
86 $fkFieldName = array_intersect($searchPaths, array_keys($fields))[0] ?? NULL;
87 if ($fkFieldName && !empty($fields[$fkFieldName]['fk_entity'])) {
88 $newFieldName = substr($fieldName, 1 + strlen($fkFieldName));
89 return civicrm_api4($fields[$fkFieldName]['fk_entity'], 'getFields', [
90 'checkPermissions' => $this->checkPermissions,
91 'where' => [['name', '=', $newFieldName]],
92 'loadOptions' => $this->loadOptions,
93 'action' => $this->action,
94 ])->first();
95 }
96 }
97
98 /**
99 * Special handling for pseudoconstant replacements.
100 *
101 * Normally this would involve calling getFields... but this IS getFields.
102 *
103 * @throws \API_Exception
104 */
105 private function formatValues() {
106 foreach (array_keys($this->values) as $key) {
107 if (strpos($key, ':')) {
108 [$fieldName, $suffix] = explode(':', $key);
109 $context = FormattingUtil::$pseudoConstantContexts[$suffix] ?? NULL;
110 if (!$context) {
111 throw new \API_Exception('Illegal expression');
112 }
113 $baoName = CoreUtil::getBAOFromApiName($this->getEntityName());
114 $options = $baoName::buildOptions($fieldName, $context);
115 $this->values[$fieldName] = FormattingUtil::replacePseudoconstant($options, $this->values[$key], TRUE);
116 unset($this->values[$key]);
117 }
118 }
119 }
120
121 public function fields() {
122 $fields = parent::fields();
123 $fields[] = [
124 'name' => 'help_pre',
125 'data_type' => 'String',
126 ];
127 $fields[] = [
128 'name' => 'help_post',
129 'data_type' => 'String',
130 ];
131 $fields[] = [
132 'name' => 'column_name',
133 'data_type' => 'String',
134 ];
135 $fields[] = [
136 'name' => 'custom_field_id',
137 'data_type' => 'Integer',
138 ];
139 $fields[] = [
140 'name' => 'custom_group_id',
141 'data_type' => 'Integer',
142 ];
143 $fields[] = [
144 'name' => 'sql_filters',
145 'data_type' => 'Array',
146 '@internal' => TRUE,
147 ];
148 $fields[] = [
149 'name' => 'sql_renderer',
150 'data_type' => 'Array',
151 '@internal' => TRUE,
152 ];
153 return $fields;
154 }
155
156 }