Commit | Line | Data |
---|---|---|
9ff5f6c0 | 1 | <?php |
4c6ce474 EM |
2 | |
3 | /** | |
4 | * Class CRM_Custom_Import_Parser_Api | |
5 | */ | |
9ff5f6c0 N |
6 | class CRM_Custom_Import_Parser_Api extends CRM_Custom_Import_Parser { |
7 | ||
8 | protected $_entity = ''; | |
be2fb01f CW |
9 | protected $_fields = []; |
10 | protected $_requiredFields = []; | |
11 | protected $_dateFields = []; | |
9ff5f6c0 N |
12 | protected $_multipleCustomData = ''; |
13 | ||
14 | /** | |
fe482240 | 15 | * Params for the current entity being prepared for the api. |
9ff5f6c0 N |
16 | * @var array |
17 | */ | |
be2fb01f | 18 | protected $_params = []; |
353ffa53 | 19 | |
9ff5f6c0 | 20 | /** |
7a9ab499 EM |
21 | * Class constructor. |
22 | * | |
23 | * @param array $mapperKeys | |
24 | * @param null $mapperLocType | |
25 | * @param null $mapperPhoneType | |
9ff5f6c0 | 26 | */ |
00be9182 | 27 | public function __construct(&$mapperKeys, $mapperLocType = NULL, $mapperPhoneType = NULL) { |
9ff5f6c0 N |
28 | parent::__construct(); |
29 | $this->_mapperKeys = &$mapperKeys; | |
30 | } | |
353ffa53 | 31 | |
00be9182 | 32 | public function setFields() { |
9ff5f6c0 N |
33 | $customGroupID = $this->_multipleCustomData; |
34 | $importableFields = $this->getGroupFieldsForImport($customGroupID, $this); | |
be2fb01f | 35 | $this->_fields = array_merge([ |
518fa0ee SL |
36 | 'do_not_import' => ['title' => ts('- do not import -')], |
37 | 'contact_id' => ['title' => ts('Contact ID')], | |
38 | 'external_identifier' => ['title' => ts('External Identifier')], | |
39 | ], $importableFields); | |
9ff5f6c0 N |
40 | } |
41 | ||
42 | /** | |
100fef9d | 43 | * The initializer code, called before the processing |
9ff5f6c0 N |
44 | * |
45 | * @return void | |
9ff5f6c0 | 46 | */ |
00be9182 | 47 | public function init() { |
9ff5f6c0 N |
48 | $this->setFields(); |
49 | $fields = $this->_fields; | |
50 | $hasLocationType = FALSE; | |
51 | ||
52 | foreach ($fields as $name => $field) { | |
53 | $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT); | |
54 | $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//'); | |
55 | $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//'); | |
56 | $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern'], $hasLocationType); | |
57 | } | |
58 | $this->setActiveFields($this->_mapperKeys); | |
59 | } | |
60 | ||
61 | /** | |
fe482240 | 62 | * Handle the values in mapField mode. |
9ff5f6c0 | 63 | * |
c4ca4892 TO |
64 | * @param array $values |
65 | * The array of values belonging to this line. | |
9ff5f6c0 | 66 | * |
408b79bf | 67 | * @return bool |
9ff5f6c0 | 68 | */ |
00be9182 | 69 | public function mapField(&$values) { |
9ff5f6c0 N |
70 | return CRM_Import_Parser::VALID; |
71 | } | |
72 | ||
73 | /** | |
fe482240 | 74 | * Handle the values in preview mode. |
9ff5f6c0 | 75 | * |
c4ca4892 TO |
76 | * @param array $values |
77 | * The array of values belonging to this line. | |
9ff5f6c0 | 78 | * |
408b79bf | 79 | * @return bool |
a6c01b45 | 80 | * the result of this processing |
9ff5f6c0 | 81 | */ |
00be9182 | 82 | public function preview(&$values) { |
9ff5f6c0 N |
83 | return $this->summary($values); |
84 | } | |
85 | ||
86 | /** | |
c4ca4892 TO |
87 | * @param array $values |
88 | * The array of values belonging to this line. | |
9ff5f6c0 | 89 | * |
408b79bf | 90 | * @return bool |
a6c01b45 | 91 | * the result of this processing |
16b10e64 CW |
92 | * It is called from both the preview & the import actions |
93 | * | |
9ff5f6c0 N |
94 | * @see CRM_Custom_Import_Parser_BaseClass::summary() |
95 | */ | |
00be9182 | 96 | public function summary(&$values) { |
e8646905 | 97 | $erroneousField = NULL; |
353ffa53 | 98 | $response = $this->setActiveFieldValues($values, $erroneousField); |
e8646905 TO |
99 | $errorRequired = FALSE; |
100 | $missingField = ''; | |
101 | $this->_params = &$this->getActiveFieldParams(); | |
102 | ||
103 | $formatted = $this->_params; | |
104 | $this->_updateWithId = FALSE; | |
105 | $this->_parseStreetAddress = CRM_Utils_Array::value('street_address_parsing', CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options'), FALSE); | |
106 | ||
107 | $this->_params = $this->getActiveFieldParams(); | |
108 | foreach ($this->_requiredFields as $requiredField) { | |
109 | if (empty($this->_params[$requiredField])) { | |
110 | $errorRequired = TRUE; | |
111 | $missingField .= ' ' . $requiredField; | |
112 | CRM_Contact_Import_Parser_Contact::addToErrorMsg($this->_entity, $requiredField); | |
113 | } | |
114 | } | |
115 | ||
116 | if ($errorRequired) { | |
117 | array_unshift($values, ts('Missing required field(s) :') . $missingField); | |
118 | return CRM_Import_Parser::ERROR; | |
119 | } | |
120 | ||
121 | $errorMessage = NULL; | |
122 | ||
123 | $contactType = $this->_contactType ? $this->_contactType : 'Organization'; | |
be2fb01f | 124 | CRM_Contact_Import_Parser_Contact::isErrorInCustomData($this->_params + ['contact_type' => $contactType], $errorMessage, $this->_contactSubType, NULL); |
e8646905 TO |
125 | |
126 | // pseudoconstants | |
127 | if ($errorMessage) { | |
128 | $tempMsg = "Invalid value for field(s) : $errorMessage"; | |
129 | array_unshift($values, $tempMsg); | |
130 | $errorMessage = NULL; | |
131 | return CRM_Import_Parser::ERROR; | |
132 | } | |
133 | return CRM_Import_Parser::VALID; | |
9ff5f6c0 N |
134 | } |
135 | ||
136 | /** | |
fe482240 | 137 | * Handle the values in import mode. |
9ff5f6c0 | 138 | * |
c4ca4892 TO |
139 | * @param int $onDuplicate |
140 | * The code for what action to take on duplicates. | |
141 | * @param array $values | |
142 | * The array of values belonging to this line. | |
9ff5f6c0 | 143 | * |
408b79bf | 144 | * @return bool |
a6c01b45 | 145 | * the result of this processing |
9ff5f6c0 | 146 | */ |
00be9182 | 147 | public function import($onDuplicate, &$values) { |
9ff5f6c0 N |
148 | $response = $this->summary($values); |
149 | if ($response != CRM_Import_Parser::VALID) { | |
9ff5f6c0 N |
150 | return $response; |
151 | } | |
152 | ||
153 | $this->_updateWithId = FALSE; | |
154 | $this->_parseStreetAddress = CRM_Utils_Array::value('street_address_parsing', CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options'), FALSE); | |
155 | ||
9ff5f6c0 | 156 | $contactType = $this->_contactType ? $this->_contactType : 'Organization'; |
be2fb01f | 157 | $formatted = [ |
9ff5f6c0 | 158 | 'contact_type' => $contactType, |
be2fb01f | 159 | ]; |
9ff5f6c0 | 160 | |
22a82042 FVL |
161 | if (isset($this->_params['external_identifier']) && !isset($this->_params['contact_id'])) { |
162 | $checkCid = new CRM_Contact_DAO_Contact(); | |
163 | $checkCid->external_identifier = $this->_params['external_identifier']; | |
164 | $checkCid->find(TRUE); | |
165 | $formatted['id'] = $checkCid->id; | |
cbfecf29 | 166 | } |
75ec7cfb | 167 | else { |
22a82042 FVL |
168 | $formatted['id'] = $this->_params['contact_id']; |
169 | } | |
9ff5f6c0 | 170 | |
f54e87d9 | 171 | $this->formatCommonData($this->_params, $formatted); |
22e263ad | 172 | foreach ($formatted['custom'] as $key => $val) { |
92fcb95f | 173 | $this->_params['custom_' . $key] = $val[-1]['value']; |
9ff5f6c0 N |
174 | } |
175 | $this->_params['skipRecentView'] = TRUE; | |
176 | $this->_params['check_permissions'] = TRUE; | |
177 | $this->_params['entity_id'] = $formatted['id']; | |
92e4c2a5 | 178 | try { |
9ff5f6c0 N |
179 | civicrm_api3('custom_value', 'create', $this->_params); |
180 | } | |
353ffa53 | 181 | catch (CiviCRM_API3_Exception $e) { |
9ff5f6c0 N |
182 | $error = $e->getMessage(); |
183 | array_unshift($values, $error); | |
184 | return CRM_Import_Parser::ERROR; | |
185 | } | |
186 | } | |
187 | ||
188 | /** | |
68f3bda5 | 189 | * Adapted from CRM_Contact_Import_Parser_Contact::formatCommonData |
f54e87d9 CW |
190 | * |
191 | * TODO: Is this function even necessary? All values get passed to the api anyway. | |
9ff5f6c0 | 192 | * |
f54e87d9 CW |
193 | * @param array $params |
194 | * Contain record values. | |
195 | * @param array $formatted | |
196 | * Array of formatted data. | |
9ff5f6c0 | 197 | */ |
54847287 | 198 | private function formatCommonData($params, &$formatted) { |
f54e87d9 CW |
199 | |
200 | $customFields = CRM_Core_BAO_CustomField::getFields(NULL); | |
201 | ||
202 | //format date first | |
9ff5f6c0 | 203 | $session = CRM_Core_Session::singleton(); |
f54e87d9 CW |
204 | $dateType = $session->get("dateTypes"); |
205 | foreach ($params as $key => $val) { | |
206 | $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key); | |
207 | if ($customFieldID) { | |
208 | //we should not update Date to null, CRM-4062 | |
209 | if ($val && ($customFields[$customFieldID]['data_type'] == 'Date')) { | |
210 | //CRM-21267 | |
211 | CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key); | |
212 | } | |
213 | elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { | |
214 | if (empty($val) && !is_numeric($val)) { | |
215 | //retain earlier value when Import mode is `Fill` | |
216 | unset($params[$key]); | |
217 | } | |
218 | else { | |
219 | $params[$key] = CRM_Utils_String::strtoboolstr($val); | |
220 | } | |
221 | } | |
222 | } | |
223 | } | |
224 | ||
225 | //now format custom data. | |
226 | foreach ($params as $key => $field) { | |
227 | ||
228 | if ($key == 'id' && isset($field)) { | |
229 | $formatted[$key] = $field; | |
230 | } | |
231 | ||
232 | //Handling Custom Data | |
233 | if (($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) && | |
234 | array_key_exists($customFieldID, $customFields) | |
235 | ) { | |
236 | ||
237 | $extends = $customFields[$customFieldID]['extends'] ?? NULL; | |
238 | $htmlType = $customFields[$customFieldID]['html_type'] ?? NULL; | |
239 | $dataType = $customFields[$customFieldID]['data_type'] ?? NULL; | |
240 | $serialized = CRM_Core_BAO_CustomField::isSerialized($customFields[$customFieldID]); | |
241 | ||
242 | if (!$serialized && in_array($htmlType, ['Select', 'Radio', 'Autocomplete-Select']) && in_array($dataType, ['String', 'Int'])) { | |
243 | $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE); | |
244 | foreach ($customOption as $customValue) { | |
245 | $val = $customValue['value'] ?? NULL; | |
246 | $label = strtolower($customValue['label'] ?? ''); | |
247 | $value = strtolower(trim($formatted[$key])); | |
248 | if (($value == $label) || ($value == strtolower($val))) { | |
249 | $params[$key] = $formatted[$key] = $val; | |
250 | } | |
251 | } | |
252 | } | |
253 | elseif ($serialized && !empty($formatted[$key]) && !empty($params[$key])) { | |
254 | $mulValues = explode(',', $formatted[$key]); | |
255 | $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE); | |
256 | $formatted[$key] = []; | |
257 | $params[$key] = []; | |
258 | foreach ($mulValues as $v1) { | |
259 | foreach ($customOption as $v2) { | |
260 | if ((strtolower($v2['label']) == strtolower(trim($v1))) || | |
261 | (strtolower($v2['value']) == strtolower(trim($v1))) | |
262 | ) { | |
263 | if ($htmlType == 'CheckBox') { | |
264 | $params[$key][$v2['value']] = $formatted[$key][$v2['value']] = 1; | |
265 | } | |
266 | else { | |
267 | $params[$key][] = $formatted[$key][] = $v2['value']; | |
268 | } | |
269 | } | |
270 | } | |
271 | } | |
272 | } | |
273 | } | |
274 | } | |
9ff5f6c0 | 275 | |
f54e87d9 CW |
276 | if (!empty($key) && ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) && array_key_exists($customFieldID, $customFields)) { |
277 | // @todo calling api functions directly is not supported | |
278 | _civicrm_api3_custom_format_params($params, $formatted, $extends); | |
9ff5f6c0 N |
279 | } |
280 | } | |
281 | ||
282 | /** | |
fe482240 | 283 | * Set import entity. |
9ff5f6c0 N |
284 | * @param string $entity |
285 | */ | |
00be9182 | 286 | public function setEntity($entity) { |
9ff5f6c0 N |
287 | $this->_entity = $entity; |
288 | $this->_multipleCustomData = $entity; | |
289 | } | |
290 | ||
291 | /** | |
100fef9d | 292 | * The initializer code, called before the processing |
9ff5f6c0 N |
293 | * |
294 | * @return void | |
9ff5f6c0 | 295 | */ |
e8646905 TO |
296 | public function fini() { |
297 | } | |
9ff5f6c0 N |
298 | |
299 | /** | |
300 | * Return the field ids and names (with groups) for import purpose. | |
301 | * | |
c4ca4892 TO |
302 | * @param int $id |
303 | * Custom group ID. | |
9ff5f6c0 | 304 | * |
a6c01b45 | 305 | * @return array |
9ff5f6c0 | 306 | * |
9ff5f6c0 | 307 | */ |
e8646905 | 308 | public function getGroupFieldsForImport($id) { |
be2fb01f CW |
309 | $importableFields = []; |
310 | $params = ['custom_group_id' => $id]; | |
9ff5f6c0 N |
311 | $allFields = civicrm_api3('custom_field', 'get', $params); |
312 | $fields = $allFields['values']; | |
313 | foreach ($fields as $id => $values) { | |
9c1bc317 | 314 | $datatype = $values['data_type'] ?? NULL; |
481a74f4 | 315 | if ($datatype == 'File') { |
9ff5f6c0 N |
316 | continue; |
317 | } | |
318 | /* generate the key for the fields array */ | |
319 | $key = "custom_$id"; | |
320 | $regexp = preg_replace('/[.,;:!?]/', '', CRM_Utils_Array::value(0, $values)); | |
be2fb01f | 321 | $importableFields[$key] = [ |
9ff5f6c0 | 322 | 'name' => $key, |
6b409353 | 323 | 'title' => $values['label'] ?? NULL, |
9ff5f6c0 N |
324 | 'headerPattern' => '/' . preg_quote($regexp, '/') . '/', |
325 | 'import' => 1, | |
326 | 'custom_field_id' => $id, | |
6b409353 CW |
327 | 'options_per_line' => $values['options_per_line'] ?? NULL, |
328 | 'data_type' => $values['data_type'] ?? NULL, | |
329 | 'html_type' => $values['html_type'] ?? NULL, | |
330 | 'is_search_range' => $values['is_search_range'] ?? NULL, | |
be2fb01f | 331 | ]; |
9ff5f6c0 | 332 | if (CRM_Utils_Array::value('html_type', $values) == 'Select Date') { |
9c1bc317 CW |
333 | $importableFields[$key]['date_format'] = $values['date_format'] ?? NULL; |
334 | $importableFields[$key]['time_format'] = $values['time_format'] ?? NULL; | |
9ff5f6c0 N |
335 | $this->_dateFields[] = $key; |
336 | } | |
337 | } | |
338 | return $importableFields; | |
339 | } | |
96025800 | 340 | |
fd31fa4c | 341 | } |