Merge pull request #19800 from eileenmcnaughton/gettypes
[civicrm-core.git] / Civi / Api4 / Service / Spec / SpecFormatter.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 */
18
19
19b53e5b
C
20namespace Civi\Api4\Service\Spec;
21
19b53e5b
C
22use CRM_Core_DAO_AllCoreTables as AllCoreTables;
23
24class SpecFormatter {
25
26 /**
27 * @param FieldSpec[] $fields
28 * @param bool $includeFieldOptions
91edcf66 29 * @param array $values
19b53e5b
C
30 *
31 * @return array
32 */
91edcf66 33 public static function specToArray($fields, $includeFieldOptions = FALSE, $values = []) {
19b53e5b
C
34 $fieldArray = [];
35
36 foreach ($fields as $field) {
37 if ($includeFieldOptions) {
bb6bfd68 38 $field->getOptions($values, $includeFieldOptions);
19b53e5b
C
39 }
40 $fieldArray[$field->getName()] = $field->toArray();
41 }
42
43 return $fieldArray;
44 }
45
46 /**
47 * @param array $data
48 * @param string $entity
49 *
50 * @return FieldSpec
51 */
52 public static function arrayToField(array $data, $entity) {
53 $dataTypeName = self::getDataType($data);
54
55 if (!empty($data['custom_group_id'])) {
56 $field = new CustomFieldSpec($data['name'], $entity, $dataTypeName);
57 if (strpos($entity, 'Custom_') !== 0) {
58 $field->setName($data['custom_group.name'] . '.' . $data['name']);
59 }
60 else {
61 $field->setCustomTableName($data['custom_group.table_name']);
19b53e5b 62 }
a689294c 63 $field->setColumnName($data['column_name']);
1b8e3bc8 64 $field->setCustomFieldId($data['id'] ?? NULL);
19b53e5b 65 $field->setCustomGroupName($data['custom_group.name']);
b751bdc9
CW
66 $field->setTitle($data['label']);
67 $field->setLabel($data['custom_group.title'] . ': ' . $data['label']);
1b8e3bc8
CW
68 $field->setHelpPre($data['help_pre'] ?? NULL);
69 $field->setHelpPost($data['help_post'] ?? NULL);
19b53e5b 70 $field->setOptions(self::customFieldHasOptions($data));
34745448 71 $field->setreadonly($data['is_view']);
19b53e5b
C
72 }
73 else {
1b8e3bc8 74 $name = $data['name'] ?? NULL;
19b53e5b 75 $field = new FieldSpec($name, $entity, $dataTypeName);
1b8e3bc8
CW
76 $field->setRequired(!empty($data['required']));
77 $field->setTitle($data['title'] ?? NULL);
b6b6cb2d 78 $field->setLabel($data['html']['label'] ?? NULL);
19b53e5b 79 $field->setOptions(!empty($data['pseudoconstant']));
34745448 80 $field->setreadonly(!empty($data['readonly']));
19b53e5b 81 }
08a06697 82 $field->setSerialize($data['serialize'] ?? NULL);
1b8e3bc8
CW
83 $field->setDefaultValue($data['default'] ?? NULL);
84 $field->setDescription($data['description'] ?? NULL);
19b53e5b
C
85 self::setInputTypeAndAttrs($field, $data, $dataTypeName);
86
1b8e3bc8
CW
87 $field->setPermission($data['permission'] ?? NULL);
88 $fkAPIName = $data['FKApiName'] ?? NULL;
89 $fkClassName = $data['FKClassName'] ?? NULL;
19b53e5b
C
90 if ($fkAPIName || $fkClassName) {
91 $field->setFkEntity($fkAPIName ?: AllCoreTables::getBriefName($fkClassName));
92 }
93
94 return $field;
95 }
96
97 /**
98 * Does this custom field have options
99 *
100 * @param array $field
101 * @return bool
102 */
103 private static function customFieldHasOptions($field) {
104 // This will include boolean fields with Yes/No options.
105 if (in_array($field['html_type'], ['Radio', 'CheckBox'])) {
106 return TRUE;
107 }
108 // Do this before the "Select" string search because date fields have a "Select Date" html_type
109 // and contactRef fields have an "Autocomplete-Select" html_type - contacts are an FK not an option list.
110 if (in_array($field['data_type'], ['ContactReference', 'Date'])) {
111 return FALSE;
112 }
113 if (strpos($field['html_type'], 'Select') !== FALSE) {
114 return TRUE;
115 }
116 return !empty($field['option_group_id']);
117 }
118
119 /**
120 * Get the data type from an array. Defaults to 'data_type' with fallback to
121 * mapping for the integer value 'type'
122 *
123 * @param array $data
124 *
125 * @return string
126 */
127 private static function getDataType(array $data) {
128 if (isset($data['data_type'])) {
129 return !empty($data['time_format']) ? 'Timestamp' : $data['data_type'];
130 }
131
1b8e3bc8 132 $dataTypeInt = $data['type'] ?? NULL;
19b53e5b
C
133 $dataTypeName = \CRM_Utils_Type::typeToString($dataTypeInt);
134
135 return $dataTypeName;
136 }
137
138 /**
139 * @param \Civi\Api4\Service\Spec\FieldSpec $fieldSpec
140 * @param array $data
141 * @param string $dataTypeName
142 */
143 public static function setInputTypeAndAttrs(FieldSpec &$fieldSpec, $data, $dataTypeName) {
1b8e3bc8
CW
144 $inputType = $data['html']['type'] ?? $data['html_type'] ?? NULL;
145 $inputAttrs = $data['html'] ?? [];
19b53e5b
C
146 unset($inputAttrs['type']);
147
19b53e5b 148 $map = [
19b53e5b
C
149 'Select Date' => 'Date',
150 'Link' => 'Url',
151 ];
1b8e3bc8 152 $inputType = $map[$inputType] ?? $inputType;
08a06697
CW
153 if ($inputType == 'Select' && !empty($data['serialize'])) {
154 $inputAttrs['multiple'] = TRUE;
155 }
19b53e5b
C
156 if ($inputType == 'Date' && !empty($inputAttrs['formatType'])) {
157 self::setLegacyDateFormat($inputAttrs);
158 }
159 // Date/time settings from custom fields
160 if ($inputType == 'Date' && !empty($data['custom_group_id'])) {
161 $inputAttrs['time'] = empty($data['time_format']) ? FALSE : ($data['time_format'] == 1 ? 12 : 24);
162 $inputAttrs['date'] = $data['date_format'];
163 $inputAttrs['start_date_years'] = (int) $data['start_date_years'];
164 $inputAttrs['end_date_years'] = (int) $data['end_date_years'];
165 }
166 if ($inputType == 'Text' && !empty($data['maxlength'])) {
167 $inputAttrs['maxlength'] = (int) $data['maxlength'];
168 }
169 if ($inputType == 'TextArea') {
170 foreach (['rows', 'cols', 'note_rows', 'note_cols'] as $prop) {
171 if (!empty($data[$prop])) {
172 $inputAttrs[str_replace('note_', '', $prop)] = (int) $data[$prop];
173 }
174 }
175 }
0dcd942c
CW
176 // Ensure all keys use lower_case not camelCase
177 foreach ($inputAttrs as $key => $val) {
178 if ($key !== strtolower($key)) {
179 unset($inputAttrs[$key]);
180 $key = strtolower(preg_replace('/(?=[A-Z])/', '_$0', $key));
181 $inputAttrs[$key] = $val;
182 }
183 }
19b53e5b
C
184 $fieldSpec
185 ->setInputType($inputType)
186 ->setInputAttrs($inputAttrs);
187 }
188
189 /**
190 * @param array $inputAttrs
191 */
192 private static function setLegacyDateFormat(&$inputAttrs) {
193 if (empty(\Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']])) {
194 \Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']] = [];
195 $params = ['name' => $inputAttrs['formatType']];
196 \CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_PreferencesDate', $params, \Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']]);
197 }
198 $dateFormat = \Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']];
199 unset($inputAttrs['formatType']);
200 $inputAttrs['time'] = !empty($dateFormat['time_format']);
201 $inputAttrs['date'] = TRUE;
202 $inputAttrs['start_date_years'] = (int) $dateFormat['start'];
203 $inputAttrs['end_date_years'] = (int) $dateFormat['end'];
204 }
205
206}