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