[REF] [Import] Extract getContactType
[civicrm-core.git] / CRM / Contact / Import / Form / MapField.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * This class gets the name of the file to upload.
20 */
21 class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
22
23 use CRM_Contact_Import_MetadataTrait;
24
25 /**
26 * An array of all contact fields with
27 * formatted custom field names.
28 *
29 * @var array
30 */
31 protected $_formattedFieldNames;
32
33 /**
34 * On duplicate.
35 *
36 * @var int
37 */
38 public $_onDuplicate;
39
40 protected $_dedupeFields;
41
42 protected static $customFields;
43
44 /**
45 * Attempt to match header labels with our mapper fields.
46 *
47 * FIXME: This is essentially the same function as parent::defaultFromHeader
48 *
49 * @param string $columnName name of column header
50 *
51 * @return string
52 */
53 public function defaultFromColumnName($columnName) {
54
55 if (!preg_match('/^[a-z0-9 ]$/i', $columnName)) {
56 if ($columnKey = array_search($columnName, $this->getFieldTitles())) {
57 $this->_fieldUsed[$columnKey] = TRUE;
58 return $columnKey;
59 }
60 }
61
62 foreach ($this->getHeaderPatterns() as $key => $re) {
63 // Skip empty key/patterns
64 if (!$key || !$re || strlen("$re") < 5) {
65 continue;
66 }
67
68 if (preg_match($re, $columnName)) {
69 $this->_fieldUsed[$key] = TRUE;
70 return $key;
71 }
72 }
73 return '';
74 }
75
76 /**
77 * Set variables up before form is built.
78 *
79 * @throws \API_Exception
80 * @throws \CRM_Core_Exception
81 * @throws \Civi\API\Exception\UnauthorizedException
82 */
83 public function preProcess() {
84 $this->_mapperFields = $this->get('fields');
85 $this->_importTableName = $this->get('importTableName');
86 $this->_onDuplicate = $this->get('onDuplicate');
87 $this->_contactSubType = $this->get('contactSubType');
88 $highlightedFields = [];
89 $highlightedFields[] = 'email';
90 $highlightedFields[] = 'external_identifier';
91 //format custom field names, CRM-2676
92 $contactType = $this->getContactType();
93 switch ($this->get('contactType')) {
94 case CRM_Import_Parser::CONTACT_INDIVIDUAL:
95 $highlightedFields[] = 'first_name';
96 $highlightedFields[] = 'last_name';
97 break;
98
99 case CRM_Import_Parser::CONTACT_HOUSEHOLD:
100 $highlightedFields[] = 'household_name';
101 break;
102
103 case CRM_Import_Parser::CONTACT_ORGANIZATION:
104 $highlightedFields[] = 'organization_name';
105 break;
106 }
107 $this->_contactType = $contactType;
108 if ($this->_onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP) {
109 unset($this->_mapperFields['id']);
110 }
111 else {
112 $highlightedFields[] = 'id';
113 }
114
115 if ($this->_onDuplicate != CRM_Import_Parser::DUPLICATE_NOCHECK) {
116 //Mark Dedupe Rule Fields as required, since it's used in matching contact
117 foreach (CRM_Contact_BAO_ContactType::basicTypes() as $cType) {
118 $ruleParams = [
119 'contact_type' => $cType,
120 'used' => 'Unsupervised',
121 ];
122 $this->_dedupeFields[$cType] = CRM_Dedupe_BAO_DedupeRule::dedupeRuleFields($ruleParams);
123 }
124
125 //Modify mapper fields title if fields are present in dedupe rule
126 if (is_array($this->_dedupeFields[$contactType])) {
127 foreach ($this->_dedupeFields[$contactType] as $val) {
128 if ($valTitle = CRM_Utils_Array::value($val, $this->_mapperFields)) {
129 $this->_mapperFields[$val] = $valTitle . ' (match to contact)';
130 }
131 }
132 }
133 }
134 // retrieve and highlight required custom fields
135 $formattedFieldNames = $this->formatCustomFieldName($this->_mapperFields);
136 self::$customFields = CRM_Core_BAO_CustomField::getFields($this->_contactType);
137 foreach (self::$customFields as $key => $attr) {
138 if (!empty($attr['is_required'])) {
139 $highlightedFields[] = "custom_$key";
140 }
141 }
142 $this->assign('highlightedFields', $highlightedFields);
143 $this->_formattedFieldNames[$contactType] = $this->_mapperFields = array_merge($this->_mapperFields, $formattedFieldNames);
144
145 $columnNames = $this->getColumnHeaders();
146 $this->assign('showColNames', !empty($columnNames));
147
148 $this->_columnCount = $this->getNumberOfColumns();
149 $this->_columnNames = $columnNames;
150 $this->assign('columnNames', $this->getColumnHeaders());
151 //$this->_columnCount = $this->get( 'columnCount' );
152 $this->assign('columnCount', $this->_columnCount);
153 $this->_dataValues = array_values($this->getDataRows(2));
154 $this->assign('dataValues', $this->_dataValues);
155 }
156
157 /**
158 * Build the form object.
159 *
160 * @throws \CiviCRM_API3_Exception
161 */
162 public function buildQuickForm() {
163 $savedMappingID = (int) $this->get('savedMapping');
164 $this->buildSavedMappingFields($savedMappingID);
165
166 $this->addFormRule(['CRM_Contact_Import_Form_MapField', 'formRule']);
167
168 //-------- end of saved mapping stuff ---------
169
170 $defaults = [];
171 $mapperKeys = array_keys($this->_mapperFields);
172 $hasColumnNames = !empty($this->_columnNames);
173 $hasLocationTypes = $this->get('fieldTypes');
174
175 $this->_location_types = ['Primary' => ts('Primary')] + CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
176 $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
177
178 // Pass default location to js
179 if ($defaultLocationType) {
180 $this->assign('defaultLocationType', $defaultLocationType->id);
181 $this->assign('defaultLocationTypeLabel', $this->_location_types[$defaultLocationType->id]);
182 }
183
184 /* Initialize all field usages to false */
185 foreach ($mapperKeys as $key) {
186 $this->_fieldUsed[$key] = FALSE;
187 }
188
189 $sel1 = $this->_mapperFields;
190 $sel2[''] = NULL;
191
192 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
193 $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
194 $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
195
196 foreach ($this->_location_types as $key => $value) {
197 $sel3['phone'][$key] = &$phoneTypes;
198 $sel3['phone_ext'][$key] = &$phoneTypes;
199 //build array for IM service provider type for contact
200 $sel3['im'][$key] = &$imProviders;
201 }
202
203 $sel4 = NULL;
204
205 // store and cache all relationship types
206 $contactRelation = new CRM_Contact_DAO_RelationshipType();
207 $contactRelation->find();
208 while ($contactRelation->fetch()) {
209 $contactRelationCache[$contactRelation->id] = [];
210 $contactRelationCache[$contactRelation->id]['contact_type_a'] = $contactRelation->contact_type_a;
211 $contactRelationCache[$contactRelation->id]['contact_sub_type_a'] = $contactRelation->contact_sub_type_a;
212 $contactRelationCache[$contactRelation->id]['contact_type_b'] = $contactRelation->contact_type_b;
213 $contactRelationCache[$contactRelation->id]['contact_sub_type_b'] = $contactRelation->contact_sub_type_b;
214 }
215 $highlightedFields = $highlightedRelFields = [];
216
217 $highlightedFields['email'] = 'All';
218 $highlightedFields['external_identifier'] = 'All';
219 $highlightedFields['first_name'] = 'Individual';
220 $highlightedFields['last_name'] = 'Individual';
221 $highlightedFields['household_name'] = 'Household';
222 $highlightedFields['organization_name'] = 'Organization';
223
224 foreach ($mapperKeys as $key) {
225 // check if there is a _a_b or _b_a in the key
226 if (strpos($key, '_a_b') || strpos($key, '_b_a')) {
227 [$id, $first, $second] = explode('_', $key);
228 }
229 else {
230 $id = $first = $second = NULL;
231 }
232 if (($first === 'a' && $second === 'b') || ($first === 'b' && $second === 'a')) {
233 $cType = $contactRelationCache[$id]["contact_type_{$second}"];
234
235 //CRM-5125 for contact subtype specific relationshiptypes
236 $cSubType = NULL;
237 if (!empty($contactRelationCache[$id]["contact_sub_type_{$second}"])) {
238 $cSubType = $contactRelationCache[$id]["contact_sub_type_{$second}"];
239 }
240
241 if (!$cType) {
242 $cType = 'All';
243 }
244
245 $relatedFields = CRM_Contact_BAO_Contact::importableFields($cType);
246 unset($relatedFields['']);
247 $values = [];
248 foreach ($relatedFields as $name => $field) {
249 $values[$name] = $field['title'];
250 if (isset($hasLocationTypes[$name])) {
251 $sel3[$key][$name] = $this->_location_types;
252 }
253 elseif ($name === 'url') {
254 $sel3[$key][$name] = $websiteTypes;
255 }
256 else {
257 $sel3[$name] = NULL;
258 }
259 }
260
261 //fix to append custom group name to field name, CRM-2676
262 if (empty($this->_formattedFieldNames[$cType]) || $cType == $this->_contactType) {
263 $this->_formattedFieldNames[$cType] = $this->formatCustomFieldName($values);
264 }
265
266 $this->_formattedFieldNames[$cType] = array_merge($values, $this->_formattedFieldNames[$cType]);
267
268 //Modified the Relationship fields if the fields are
269 //present in dedupe rule
270 if ($this->_onDuplicate != CRM_Import_Parser::DUPLICATE_NOCHECK && !empty($this->_dedupeFields[$cType]) &&
271 is_array($this->_dedupeFields[$cType])
272 ) {
273 static $cTypeArray = [];
274 if ($cType != $this->_contactType && !in_array($cType, $cTypeArray)) {
275 foreach ($this->_dedupeFields[$cType] as $val) {
276 if ($valTitle = CRM_Utils_Array::value($val, $this->_formattedFieldNames[$cType])) {
277 $this->_formattedFieldNames[$cType][$val] = $valTitle . ' (match to contact)';
278 }
279 }
280 $cTypeArray[] = $cType;
281 }
282 }
283
284 foreach ($highlightedFields as $k => $v) {
285 if ($v == $cType || $v === 'All') {
286 $highlightedRelFields[$key][] = $k;
287 }
288 }
289 $this->assign('highlightedRelFields', $highlightedRelFields);
290 $sel2[$key] = $this->_formattedFieldNames[$cType];
291
292 if (!empty($cSubType)) {
293 //custom fields for sub type
294 $subTypeFields = CRM_Core_BAO_CustomField::getFieldsForImport($cSubType);
295
296 if (!empty($subTypeFields)) {
297 $subType = NULL;
298 foreach ($subTypeFields as $customSubTypeField => $details) {
299 $subType[$customSubTypeField] = $details['title'];
300 $sel2[$key] = array_merge($sel2[$key], $this->formatCustomFieldName($subType));
301 }
302 }
303 }
304
305 foreach ($this->_location_types as $k => $value) {
306 $sel4[$key]['phone'][$k] = &$phoneTypes;
307 $sel4[$key]['phone_ext'][$k] = &$phoneTypes;
308 //build array of IM service provider for related contact
309 $sel4[$key]['im'][$k] = &$imProviders;
310 }
311 }
312 else {
313 $options = NULL;
314 if (!empty($hasLocationTypes[$key])) {
315 $options = $this->_location_types;
316 }
317 elseif ($key === 'url') {
318 $options = $websiteTypes;
319 }
320 $sel2[$key] = $options;
321 }
322 }
323
324 $js = "<script type='text/javascript'>\n";
325 $formName = 'document.forms.' . $this->_name;
326 //used to warn for mismatch column count or mismatch mapping
327 CRM_Core_Session::singleton()->setStatus(NULL);
328 $processor = new CRM_Import_ImportProcessor();
329 $processor->setMappingID($savedMappingID);
330 $processor->setFormName($formName);
331 $processor->setMetadata($this->getContactImportMetadata());
332 $processor->setContactTypeByConstant($this->get('contactType'));
333 $processor->setContactSubType($this->get('contactSubType'));
334
335 for ($i = 0; $i < $this->_columnCount; $i++) {
336 $sel = &$this->addElement('hierselect', "mapper[$i]", ts('Mapper for Field %1', [1 => $i]), NULL);
337
338 if ($this->get('savedMapping') && $processor->getFieldName($i)) {
339 $defaults["mapper[$i]"] = $processor->getSavedQuickformDefaultsForColumn($i);
340 $js .= $processor->getQuickFormJSForField($i);
341 }
342 else {
343 $js .= "swapOptions($formName, 'mapper[$i]', 0, 3, 'hs_mapper_0_');\n";
344 if ($hasColumnNames) {
345 // do array search first to see if has mapped key
346 $columnKey = array_search($this->_columnNames[$i], $this->getFieldTitles());
347 if (isset($this->_fieldUsed[$columnKey])) {
348 $defaults["mapper[$i]"] = $columnKey;
349 $this->_fieldUsed[$key] = TRUE;
350 }
351 else {
352 // Infer the default from the column names if we have them
353 $defaults["mapper[$i]"] = [
354 $this->defaultFromColumnName($this->_columnNames[$i]),
355 0,
356 ];
357 }
358 }
359 else {
360 // Otherwise guess the default from the form of the data
361 $defaults["mapper[$i]"] = [
362 $this->defaultFromData($this->getDataPatterns(), $i),
363 // $defaultLocationType->id
364 0,
365 ];
366 }
367 }
368 $sel->setOptions([$sel1, $sel2, $sel3, $sel4]);
369 }
370
371 $js .= "</script>\n";
372 $this->assign('initHideBoxes', $js);
373
374 //set warning if mismatch in more than
375 if (isset($mappingName) &&
376 ($this->_columnCount != count($mappingName))
377 ) {
378 CRM_Core_Session::singleton()->setStatus(ts('The data columns in this import file appear to be different from the saved mapping. Please verify that you have selected the correct saved mapping before continuing.'));
379 }
380
381 $this->setDefaults($defaults);
382
383 $this->addButtons([
384 [
385 'type' => 'back',
386 'name' => ts('Previous'),
387 ],
388 [
389 'type' => 'next',
390 'name' => ts('Continue'),
391 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
392 'isDefault' => TRUE,
393 ],
394 [
395 'type' => 'cancel',
396 'name' => ts('Cancel'),
397 ],
398 ]);
399 }
400
401 /**
402 * Global validation rules for the form.
403 *
404 * @param array $fields
405 * Posted values of the form.
406 *
407 * @return array
408 * list of errors to be posted back to the form
409 */
410 public static function formRule($fields) {
411 $errors = [];
412 if (!empty($fields['saveMapping'])) {
413 $nameField = $fields['saveMappingName'] ?? NULL;
414 if (empty($nameField)) {
415 $errors['saveMappingName'] = ts('Name is required to save Import Mapping');
416 }
417 else {
418 $mappingTypeId = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_Mapping', 'mapping_type_id', 'Import Contact');
419 if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) {
420 $errors['saveMappingName'] = ts('Duplicate Import Mapping Name');
421 }
422 }
423 }
424 $template = CRM_Core_Smarty::singleton();
425 if (!empty($fields['saveMapping'])) {
426 $template->assign('isCheked', TRUE);
427 }
428
429 if (!empty($errors)) {
430 $_flag = 1;
431 $assignError = new CRM_Core_Page();
432 $assignError->assign('mappingDetailsError', $_flag);
433 return $errors;
434 }
435 else {
436 return TRUE;
437 }
438 }
439
440 /**
441 * Process the mapped fields and map it into the uploaded file.
442 */
443 public function postProcess() {
444 $params = $this->controller->exportValues('MapField');
445
446 //reload the mapfield if load mapping is pressed
447 if (!empty($params['savedMapping'])) {
448 $this->set('savedMapping', $params['savedMapping']);
449 $this->controller->resetPage($this->_name);
450 return;
451 }
452 $mapperKeys = $this->controller->exportValue($this->_name, 'mapper');
453
454 $parser = $this->submit($params, $mapperKeys);
455
456 // add all the necessary variables to the form
457 $parser->set($this);
458 }
459
460 /**
461 * Format custom field name.
462 *
463 * Combine group and field name to avoid conflict.
464 *
465 * @param array $fields
466 *
467 * @return array
468 */
469 public function formatCustomFieldName($fields) {
470 //CRM-2676, replacing the conflict for same custom field name from different custom group.
471 $fieldIds = $formattedFieldNames = [];
472 foreach ($fields as $key => $value) {
473 if ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($key)) {
474 $fieldIds[] = $customFieldId;
475 }
476 }
477
478 if (!empty($fieldIds) && is_array($fieldIds)) {
479 $groupTitles = CRM_Core_BAO_CustomGroup::getGroupTitles($fieldIds);
480
481 if (!empty($groupTitles)) {
482 foreach ($groupTitles as $fId => $values) {
483 $key = "custom_{$fId}";
484 $groupTitle = $values['groupTitle'];
485 $formattedFieldNames[$key] = $fields[$key] . ' :: ' . $groupTitle;
486 }
487 }
488 }
489
490 return $formattedFieldNames;
491 }
492
493 /**
494 * Main submit function.
495 *
496 * Extracted to add testing & start refactoring.
497 *
498 * @param $params
499 * @param $mapperKeys
500 *
501 * @return \CRM_Contact_Import_Parser_Contact
502 * @throws \CiviCRM_API3_Exception
503 */
504 public function submit($params, $mapperKeys) {
505 $mapper = $mapperKeysMain = $locations = [];
506 $parserParameters = CRM_Contact_Import_Parser_Contact::getParameterForParser($this->_columnCount);
507
508 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
509 $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
510 $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
511 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
512 $locationTypes['Primary'] = ts('Primary');
513
514 for ($i = 0; $i < $this->_columnCount; $i++) {
515
516 $fldName = $mapperKeys[$i][0] ?? NULL;
517 $selOne = $mapperKeys[$i][1] ?? NULL;
518 $selTwo = $mapperKeys[$i][2] ?? NULL;
519 $selThree = $mapperKeys[$i][3] ?? NULL;
520 $mapper[$i] = $this->_mapperFields[$mapperKeys[$i][0]];
521 $mapperKeysMain[$i] = $fldName;
522
523 //need to differentiate non location elements.
524 if ($selOne && (is_numeric($selOne) || $selOne === 'Primary')) {
525 if ($fldName === 'url') {
526 $parserParameters['mapperWebsiteType'][$i] = $websiteTypes[$selOne];
527 }
528 else {
529 $locations[$i] = $locationTypes[$selOne];
530 $parserParameters['mapperLocType'][$i] = $selOne;
531 if ($selTwo && is_numeric($selTwo)) {
532 if ($fldName === 'phone' || $fldName === 'phone_ext') {
533 $parserParameters['mapperPhoneType'][$i] = $phoneTypes[$selTwo];
534 }
535 elseif ($fldName === 'im') {
536 $parserParameters['mapperImProvider'][$i] = $imProviders[$selTwo];
537 }
538 }
539 }
540 }
541
542 //relationship contact mapper info.
543 [$id, $first, $second] = CRM_Utils_System::explode('_', $fldName, 3);
544 if (($first === 'a' && $second === 'b') ||
545 ($first === 'b' && $second === 'a')
546 ) {
547 $parserParameters['mapperRelated'][$i] = $this->_mapperFields[$fldName];
548 if ($selOne) {
549 if ($selOne === 'url') {
550 $parserParameters['relatedContactWebsiteType'][$i] = $websiteTypes[$selTwo];
551 }
552 else {
553 $parserParameters['relatedContactLocType'][$i] = $locationTypes[$selTwo] ?? NULL;
554 if ($selThree) {
555 if ($selOne === 'phone' || $selOne === 'phone_ext') {
556 $parserParameters['relatedContactPhoneType'][$i] = $phoneTypes[$selThree];
557 }
558 elseif ($selOne === 'im') {
559 $parserParameters['relatedContactImProvider'][$i] = $imProviders[$selThree];
560 }
561 }
562 }
563
564 //get the related contact type.
565 $relationType = new CRM_Contact_DAO_RelationshipType();
566 $relationType->id = $id;
567 $relationType->find(TRUE);
568 $parserParameters['relatedContactType'][$i] = $relationType->{"contact_type_$second"};
569 $parserParameters['relatedContactDetails'][$i] = $this->_formattedFieldNames[$parserParameters['relatedContactType'][$i]][$selOne];
570 }
571 }
572 }
573
574 $this->set('columnNames', $this->_columnNames);
575 $this->set('websites', $parserParameters['mapperWebsiteType']);
576 $this->set('locations', $locations);
577 $this->set('phones', $parserParameters['mapperPhoneType']);
578 $this->set('ims', $parserParameters['mapperImProvider']);
579 $this->set('related', $parserParameters['mapperRelated']);
580 $this->set('relatedContactType', $parserParameters['relatedContactType']);
581 $this->set('relatedContactDetails', $parserParameters['relatedContactDetails']);
582 $this->set('relatedContactLocType', $parserParameters['relatedContactLocType']);
583 $this->set('relatedContactPhoneType', $parserParameters['relatedContactPhoneType']);
584 $this->set('relatedContactImProvider', $parserParameters['relatedContactImProvider']);
585 $this->set('relatedContactWebsiteType', $parserParameters['relatedContactWebsiteType']);
586 $this->set('mapper', $mapper);
587
588 // store mapping Id to display it in the preview page
589 $this->set('loadMappingId', CRM_Utils_Array::value('mappingId', $params));
590
591 //Updating Mapping Records
592 if (!empty($params['updateMapping'])) {
593
594 $mappingFields = new CRM_Core_DAO_MappingField();
595 $mappingFields->mapping_id = $params['mappingId'];
596 $mappingFields->find();
597
598 $mappingFieldsId = [];
599 while ($mappingFields->fetch()) {
600 if ($mappingFields->id) {
601 $mappingFieldsId[$mappingFields->column_number] = $mappingFields->id;
602 }
603 }
604
605 for ($i = 0; $i < $this->_columnCount; $i++) {
606 $updateMappingFields = new CRM_Core_DAO_MappingField();
607 $updateMappingFields->id = $mappingFieldsId[$i] ?? NULL;
608 $updateMappingFields->mapping_id = $params['mappingId'];
609 $updateMappingFields->column_number = $i;
610
611 $mapperKeyParts = explode('_', $mapperKeys[$i][0], 3);
612 $id = $mapperKeyParts[0] ?? NULL;
613 $first = $mapperKeyParts[1] ?? NULL;
614 $second = $mapperKeyParts[2] ?? NULL;
615 if (($first == 'a' && $second == 'b') || ($first == 'b' && $second == 'a')) {
616 $updateMappingFields->relationship_type_id = $id;
617 $updateMappingFields->relationship_direction = "{$first}_{$second}";
618 $updateMappingFields->name = ucwords(str_replace("_", " ", $mapperKeys[$i][1]));
619 // get phoneType id and provider id separately
620 // before updating mappingFields of phone and IM for related contact, CRM-3140
621 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'url') {
622 $updateMappingFields->website_type_id = $mapperKeys[$i][2] ?? NULL;
623 }
624 else {
625 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'phone') {
626 $updateMappingFields->phone_type_id = $mapperKeys[$i][3] ?? NULL;
627 }
628 elseif (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'im') {
629 $updateMappingFields->im_provider_id = $mapperKeys[$i][3] ?? NULL;
630 }
631 $updateMappingFields->location_type_id = isset($mapperKeys[$i][2]) && is_numeric($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
632 }
633 }
634 else {
635 $updateMappingFields->name = $mapper[$i];
636 $updateMappingFields->relationship_type_id = 'NULL';
637 $updateMappingFields->relationship_type_direction = 'NULL';
638 // to store phoneType id and provider id separately
639 // before updating mappingFields for phone and IM, CRM-3140
640 if (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'url') {
641 $updateMappingFields->website_type_id = $mapperKeys[$i][1] ?? NULL;
642 }
643 else {
644 if (($mapperKeys[$i][0] ?? NULL) === 'phone' || ($mapperKeys[$i][0] ?? NULL) === 'phone_ext') {
645 $updateMappingFields->phone_type_id = $mapperKeys[$i][2] ?? NULL;
646 }
647 elseif (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'im') {
648 $updateMappingFields->im_provider_id = $mapperKeys[$i][2] ?? NULL;
649 }
650 $locationTypeID = $parserParameters['mapperLocType'][$i];
651 // location_type_id is NULL for non-location fields, and for Primary location.
652 $updateMappingFields->location_type_id = is_numeric($locationTypeID) ? $locationTypeID : 'null';
653 }
654 }
655 $updateMappingFields->save();
656 }
657 }
658
659 //Saving Mapping Details and Records
660 if (!empty($params['saveMapping'])) {
661 $mappingParams = [
662 'name' => $params['saveMappingName'],
663 'description' => $params['saveMappingDesc'],
664 'mapping_type_id' => 'Import Contact',
665 ];
666
667 $saveMapping = civicrm_api3('Mapping', 'create', $mappingParams);
668
669 $mappingID = NULL;
670 foreach (array_keys($this->getColumnHeaders()) as $i) {
671 $mappingID = $this->saveMappingField($mapperKeys, $saveMapping, $this->getContactType(), $i, $mapper, $parserParameters);
672 }
673 $this->set('savedMapping', $mappingID);
674 }
675
676 $parser = new CRM_Contact_Import_Parser_Contact($mapperKeysMain, $parserParameters['mapperLocType'], $parserParameters['mapperPhoneType'],
677 $parserParameters['mapperImProvider'], $parserParameters['mapperRelated'], $parserParameters['relatedContactType'],
678 $parserParameters['relatedContactDetails'], $parserParameters['relatedContactLocType'],
679 $parserParameters['relatedContactPhoneType'], $parserParameters['relatedContactImProvider'],
680 $parserParameters['mapperWebsiteType'], $parserParameters['relatedContactWebsiteType']
681 );
682 $parser->setUserJobID($this->getUserJobID());
683
684 $parser->run($this->_importTableName,
685 $mapper,
686 CRM_Import_Parser::MODE_PREVIEW,
687 $this->get('contactType'),
688 '_id',
689 '_status',
690 $this->_onDuplicate,
691 NULL, NULL, FALSE,
692 CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
693 $this->get('contactSubType'),
694 $this->getSubmittedValue('dedupe_rule_id')
695 );
696 return $parser;
697 }
698
699 /**
700 * @param $mapperKeys
701 * @param array $saveMapping
702 * @param string $cType
703 * @param int $i
704 * @param array $mapper
705 * @param array $parserParameters
706 *
707 * @return int
708 */
709 protected function saveMappingField($mapperKeys, array $saveMapping, string $cType, int $i, array $mapper, array $parserParameters): int {
710 $saveMappingFields = new CRM_Core_DAO_MappingField();
711 $saveMappingFields->mapping_id = $saveMapping['id'];
712 $saveMappingFields->contact_type = $cType;
713 $saveMappingFields->column_number = $i;
714
715 $mapperKeyParts = explode('_', $mapperKeys[$i][0], 3);
716 $id = $mapperKeyParts[0] ?? NULL;
717 $first = $mapperKeyParts[1] ?? NULL;
718 $second = $mapperKeyParts[2] ?? NULL;
719 if (($first == 'a' && $second == 'b') || ($first == 'b' && $second == 'a')) {
720 $saveMappingFields->name = ucwords(str_replace("_", " ", $mapperKeys[$i][1]));
721 $saveMappingFields->relationship_type_id = $id;
722 $saveMappingFields->relationship_direction = "{$first}_{$second}";
723 // to get phoneType id and provider id separately
724 // before saving mappingFields of phone and IM for related contact, CRM-3140
725 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'url') {
726 $saveMappingFields->website_type_id = $mapperKeys[$i][2] ?? NULL;
727 }
728 else {
729 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'phone') {
730 $saveMappingFields->phone_type_id = $mapperKeys[$i][3] ?? NULL;
731 }
732 elseif (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'im') {
733 $saveMappingFields->im_provider_id = $mapperKeys[$i][3] ?? NULL;
734 }
735 $saveMappingFields->location_type_id = (isset($mapperKeys[$i][2]) && $mapperKeys[$i][2] !== 'Primary') ? $mapperKeys[$i][2] : NULL;
736 }
737 }
738 else {
739 $saveMappingFields->name = $mapper[$i];
740 $locationTypeID = $parserParameters['mapperLocType'][$i];
741 // to get phoneType id and provider id separately
742 // before saving mappingFields of phone and IM, CRM-3140
743 if (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'url') {
744 $saveMappingFields->website_type_id = $mapperKeys[$i][1] ?? NULL;
745 }
746 else {
747 if (($mapperKeys[$i][0] ?? NULL) === 'phone' || ($mapperKeys[$i][0] ?? NULL) === 'phone_ext') {
748 $saveMappingFields->phone_type_id = $mapperKeys[$i][2] ?? NULL;
749 }
750 elseif (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'im') {
751 $saveMappingFields->im_provider_id = $mapperKeys[$i][2] ?? NULL;
752 }
753 $saveMappingFields->location_type_id = is_numeric($locationTypeID) ? $locationTypeID : NULL;
754 }
755 $saveMappingFields->relationship_type_id = NULL;
756 }
757 $saveMappingFields->save();
758 return $saveMappingFields->mapping_id;
759 }
760
761 }