Commit | Line | Data |
---|---|---|
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 |
20 | namespace Civi\Api4\Service\Spec; |
21 | ||
19b53e5b C |
22 | use CRM_Core_DAO_AllCoreTables as AllCoreTables; |
23 | ||
24 | class 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 | } |