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 | * $Id$ |
18 | * | |
19 | */ | |
20 | ||
21 | ||
19b53e5b C |
22 | namespace Civi\Api4\Service\Spec; |
23 | ||
24 | use CRM_Utils_Array as ArrayHelper; | |
25 | use CRM_Core_DAO_AllCoreTables as AllCoreTables; | |
26 | ||
27 | class SpecFormatter { | |
28 | ||
29 | /** | |
30 | * @param FieldSpec[] $fields | |
31 | * @param bool $includeFieldOptions | |
32 | * | |
33 | * @return array | |
34 | */ | |
35 | public static function specToArray($fields, $includeFieldOptions = FALSE) { | |
36 | $fieldArray = []; | |
37 | ||
38 | foreach ($fields as $field) { | |
39 | if ($includeFieldOptions) { | |
40 | $field->getOptions(); | |
41 | } | |
42 | $fieldArray[$field->getName()] = $field->toArray(); | |
43 | } | |
44 | ||
45 | return $fieldArray; | |
46 | } | |
47 | ||
48 | /** | |
49 | * @param array $data | |
50 | * @param string $entity | |
51 | * | |
52 | * @return FieldSpec | |
53 | */ | |
54 | public static function arrayToField(array $data, $entity) { | |
55 | $dataTypeName = self::getDataType($data); | |
56 | ||
57 | if (!empty($data['custom_group_id'])) { | |
58 | $field = new CustomFieldSpec($data['name'], $entity, $dataTypeName); | |
59 | if (strpos($entity, 'Custom_') !== 0) { | |
60 | $field->setName($data['custom_group.name'] . '.' . $data['name']); | |
61 | } | |
62 | else { | |
63 | $field->setCustomTableName($data['custom_group.table_name']); | |
64 | $field->setCustomFieldColumnName($data['column_name']); | |
65 | } | |
66 | $field->setCustomFieldId(ArrayHelper::value('id', $data)); | |
67 | $field->setCustomGroupName($data['custom_group.name']); | |
68 | $field->setTitle(ArrayHelper::value('label', $data)); | |
69 | $field->setOptions(self::customFieldHasOptions($data)); | |
70 | if (\CRM_Core_BAO_CustomField::isSerialized($data)) { | |
71 | $field->setSerialize(\CRM_Core_DAO::SERIALIZE_SEPARATOR_BOOKEND); | |
72 | } | |
73 | } | |
74 | else { | |
75 | $name = ArrayHelper::value('name', $data); | |
76 | $field = new FieldSpec($name, $entity, $dataTypeName); | |
77 | $field->setRequired((bool) ArrayHelper::value('required', $data, FALSE)); | |
78 | $field->setTitle(ArrayHelper::value('title', $data)); | |
79 | $field->setOptions(!empty($data['pseudoconstant'])); | |
80 | $field->setSerialize(ArrayHelper::value('serialize', $data)); | |
81 | } | |
82 | ||
83 | $field->setDefaultValue(ArrayHelper::value('default', $data)); | |
84 | $field->setDescription(ArrayHelper::value('description', $data)); | |
85 | self::setInputTypeAndAttrs($field, $data, $dataTypeName); | |
86 | ||
87 | $fkAPIName = ArrayHelper::value('FKApiName', $data); | |
88 | $fkClassName = ArrayHelper::value('FKClassName', $data); | |
89 | if ($fkAPIName || $fkClassName) { | |
90 | $field->setFkEntity($fkAPIName ?: AllCoreTables::getBriefName($fkClassName)); | |
91 | } | |
92 | ||
93 | return $field; | |
94 | } | |
95 | ||
96 | /** | |
97 | * Does this custom field have options | |
98 | * | |
99 | * @param array $field | |
100 | * @return bool | |
101 | */ | |
102 | private static function customFieldHasOptions($field) { | |
103 | // This will include boolean fields with Yes/No options. | |
104 | if (in_array($field['html_type'], ['Radio', 'CheckBox'])) { | |
105 | return TRUE; | |
106 | } | |
107 | // Do this before the "Select" string search because date fields have a "Select Date" html_type | |
108 | // and contactRef fields have an "Autocomplete-Select" html_type - contacts are an FK not an option list. | |
109 | if (in_array($field['data_type'], ['ContactReference', 'Date'])) { | |
110 | return FALSE; | |
111 | } | |
112 | if (strpos($field['html_type'], 'Select') !== FALSE) { | |
113 | return TRUE; | |
114 | } | |
115 | return !empty($field['option_group_id']); | |
116 | } | |
117 | ||
118 | /** | |
119 | * Get the data type from an array. Defaults to 'data_type' with fallback to | |
120 | * mapping for the integer value 'type' | |
121 | * | |
122 | * @param array $data | |
123 | * | |
124 | * @return string | |
125 | */ | |
126 | private static function getDataType(array $data) { | |
127 | if (isset($data['data_type'])) { | |
128 | return !empty($data['time_format']) ? 'Timestamp' : $data['data_type']; | |
129 | } | |
130 | ||
131 | $dataTypeInt = ArrayHelper::value('type', $data); | |
132 | $dataTypeName = \CRM_Utils_Type::typeToString($dataTypeInt); | |
133 | ||
134 | return $dataTypeName; | |
135 | } | |
136 | ||
137 | /** | |
138 | * @param \Civi\Api4\Service\Spec\FieldSpec $fieldSpec | |
139 | * @param array $data | |
140 | * @param string $dataTypeName | |
141 | */ | |
142 | public static function setInputTypeAndAttrs(FieldSpec &$fieldSpec, $data, $dataTypeName) { | |
143 | $inputType = isset($data['html']['type']) ? $data['html']['type'] : ArrayHelper::value('html_type', $data); | |
144 | $inputAttrs = ArrayHelper::value('html', $data, []); | |
145 | unset($inputAttrs['type']); | |
146 | ||
147 | if (!$inputType) { | |
148 | // If no html type is set, guess | |
149 | switch ($dataTypeName) { | |
150 | case 'Int': | |
151 | $inputType = 'Number'; | |
152 | $inputAttrs['min'] = 0; | |
153 | break; | |
154 | ||
155 | case 'Text': | |
156 | $inputType = ArrayHelper::value('type', $data) === \CRM_Utils_Type::T_LONGTEXT ? 'TextArea' : 'Text'; | |
157 | break; | |
158 | ||
159 | case 'Timestamp': | |
160 | $inputType = 'Date'; | |
161 | $inputAttrs['time'] = TRUE; | |
162 | break; | |
163 | ||
164 | case 'Date': | |
165 | $inputAttrs['time'] = FALSE; | |
166 | break; | |
167 | ||
168 | case 'Time': | |
169 | $inputType = 'Date'; | |
170 | $inputAttrs['time'] = TRUE; | |
171 | $inputAttrs['date'] = FALSE; | |
172 | break; | |
173 | ||
174 | default: | |
175 | $map = [ | |
176 | 'Email' => 'Email', | |
177 | 'Boolean' => 'Checkbox', | |
178 | ]; | |
179 | $inputType = ArrayHelper::value($dataTypeName, $map, 'Text'); | |
180 | } | |
181 | } | |
182 | if (strstr($inputType, 'Multi-Select') || ($inputType == 'Select' && !empty($data['serialize']))) { | |
183 | $inputAttrs['multiple'] = TRUE; | |
184 | $inputType = 'Select'; | |
185 | } | |
186 | $map = [ | |
187 | 'Select State/Province' => 'Select', | |
188 | 'Select Country' => 'Select', | |
189 | 'Select Date' => 'Date', | |
190 | 'Link' => 'Url', | |
191 | ]; | |
192 | $inputType = ArrayHelper::value($inputType, $map, $inputType); | |
193 | if ($inputType == 'Date' && !empty($inputAttrs['formatType'])) { | |
194 | self::setLegacyDateFormat($inputAttrs); | |
195 | } | |
196 | // Date/time settings from custom fields | |
197 | if ($inputType == 'Date' && !empty($data['custom_group_id'])) { | |
198 | $inputAttrs['time'] = empty($data['time_format']) ? FALSE : ($data['time_format'] == 1 ? 12 : 24); | |
199 | $inputAttrs['date'] = $data['date_format']; | |
200 | $inputAttrs['start_date_years'] = (int) $data['start_date_years']; | |
201 | $inputAttrs['end_date_years'] = (int) $data['end_date_years']; | |
202 | } | |
203 | if ($inputType == 'Text' && !empty($data['maxlength'])) { | |
204 | $inputAttrs['maxlength'] = (int) $data['maxlength']; | |
205 | } | |
206 | if ($inputType == 'TextArea') { | |
207 | foreach (['rows', 'cols', 'note_rows', 'note_cols'] as $prop) { | |
208 | if (!empty($data[$prop])) { | |
209 | $inputAttrs[str_replace('note_', '', $prop)] = (int) $data[$prop]; | |
210 | } | |
211 | } | |
212 | } | |
213 | $fieldSpec | |
214 | ->setInputType($inputType) | |
215 | ->setInputAttrs($inputAttrs); | |
216 | } | |
217 | ||
218 | /** | |
219 | * @param array $inputAttrs | |
220 | */ | |
221 | private static function setLegacyDateFormat(&$inputAttrs) { | |
222 | if (empty(\Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']])) { | |
223 | \Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']] = []; | |
224 | $params = ['name' => $inputAttrs['formatType']]; | |
225 | \CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_PreferencesDate', $params, \Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']]); | |
226 | } | |
227 | $dateFormat = \Civi::$statics['legacyDatePrefs'][$inputAttrs['formatType']]; | |
228 | unset($inputAttrs['formatType']); | |
229 | $inputAttrs['time'] = !empty($dateFormat['time_format']); | |
230 | $inputAttrs['date'] = TRUE; | |
231 | $inputAttrs['start_date_years'] = (int) $dateFormat['start']; | |
232 | $inputAttrs['end_date_years'] = (int) $dateFormat['end']; | |
233 | } | |
234 | ||
235 | } |