Merge pull request #23227 from eileenmcnaughton/inbetween_4
[civicrm-core.git] / CRM / Custom / Import / Parser / Api.php
CommitLineData
9ff5f6c0 1<?php
4c6ce474
EM
2
3/**
4 * Class CRM_Custom_Import_Parser_Api
5 */
9ff5f6c0
N
6class 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}