Merge pull request #3558 from atif-shaikh/CRM-14782-fix
[civicrm-core.git] / CRM / Contact / Import / Form / MapField.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35
36 /**
37 * This class gets the name of the file to upload
38 */
39 class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
40
41
42 /**
43 * an array of all contact fields with
44 * formatted custom field names.
45 *
46 * @var array
47 * @access protected
48 */
49 protected $_formattedFieldNames;
50
51 /**
52 * on duplicate
53 *
54 * @var int
55 */
56 public $_onDuplicate;
57
58 protected $_dedupeFields;
59
60 protected static $customFields;
61
62 /**
63 * Attempt to match header labels with our mapper fields
64 * FIXME: This is essentially the same function as parent::defaultFromHeader
65 *
66 * @param header
67 * @param mapperFields
68 *
69 * @return string
70 * @access public
71 */
72 public function defaultFromColumnName($columnName, &$patterns) {
73
74 if (!preg_match('/^[a-z0-9 ]$/i', $columnName)) {
75 if ($columnKey = array_search($columnName, $this->_mapperFields)) {
76 $this->_fieldUsed[$columnKey] = TRUE;
77 return $columnKey;
78 }
79 }
80
81 foreach ($patterns as $key => $re) {
82 // Skip empty key/patterns
83 if (!$key || !$re || strlen("$re") < 5) {
84 continue;
85 }
86
87 if (preg_match($re, $columnName)) {
88 $this->_fieldUsed[$key] = TRUE;
89 return $key;
90 }
91 }
92 return '';
93 }
94
95 /**
96 * Function to set variables up before form is built
97 *
98 * @return void
99 * @access public
100 */
101 public function preProcess() {
102 $dataSource = $this->get('dataSource');
103 $skipColumnHeader = $this->get('skipColumnHeader');
104 $this->_mapperFields = $this->get('fields');
105 $this->_importTableName = $this->get('importTableName');
106 $this->_onDuplicate = $this->get('onDuplicate');
107 $highlightedFields = array();
108 $highlightedFields[] = 'email';
109 $highlightedFields[] = 'external_identifier';
110 //format custom field names, CRM-2676
111 switch ($this->get('contactType')) {
112 case CRM_Import_Parser::CONTACT_INDIVIDUAL:
113 $contactType = 'Individual';
114 $highlightedFields[] = 'first_name';
115 $highlightedFields[] = 'last_name';
116 break;
117
118 case CRM_Import_Parser::CONTACT_HOUSEHOLD:
119 $contactType = 'Household';
120 $highlightedFields[] = 'household_name';
121 break;
122
123 case CRM_Import_Parser::CONTACT_ORGANIZATION:
124 $contactType = 'Organization';
125 $highlightedFields[] = 'organization_name';
126 break;
127 }
128 $this->_contactType = $contactType;
129 if ($this->_onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP) {
130 unset($this->_mapperFields['id']);
131 }
132 else {
133 $highlightedFields[] = 'id';
134 }
135
136 if ($this->_onDuplicate != CRM_Import_Parser::DUPLICATE_NOCHECK) {
137 //Mark Dedupe Rule Fields as required, since it's used in matching contact
138 foreach (array(
139 'Individual', 'Household', 'Organization') as $cType) {
140 $ruleParams = array(
141 'contact_type' => $cType,
142 'used' => 'Unsupervised',
143 );
144 $this->_dedupeFields[$cType] = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams);
145 }
146
147 //Modify mapper fields title if fields are present in dedupe rule
148 if (is_array($this->_dedupeFields[$contactType])) {
149 foreach ($this->_dedupeFields[$contactType] as $val) {
150 if ($valTitle = CRM_Utils_Array::value($val, $this->_mapperFields)) {
151 $this->_mapperFields[$val] = $valTitle . ' (match to contact)';
152 }
153 }
154 }
155 }
156 // retrieve and highlight required custom fields
157 $formattedFieldNames = $this->formatCustomFieldName($this->_mapperFields);
158 self::$customFields = CRM_Core_BAO_CustomField::getFields($this->_contactType);
159 foreach(self::$customFields as $key => $attr) {
160 if (!empty($attr['is_required'])) {
161 $highlightedFields[] = "custom_$key";
162 }
163 }
164 $this->assign('highlightedFields', $highlightedFields);
165 $this->_formattedFieldNames[$contactType] = $this->_mapperFields = array_merge($this->_mapperFields, $formattedFieldNames);
166
167 $columnNames = array();
168 //get original col headers from csv if present.
169 if ($dataSource == 'CRM_Import_DataSource_CSV' && $skipColumnHeader) {
170 $columnNames = $this->get('originalColHeader');
171 }
172 else {
173 // get the field names from the temp. DB table
174 $dao = new CRM_Core_DAO();
175 $db = $dao->getDatabaseConnection();
176
177 $columnsQuery = "SHOW FIELDS FROM $this->_importTableName
178 WHERE Field NOT LIKE '\_%'";
179 $columnsResult = $db->query($columnsQuery);
180 while ($row = $columnsResult->fetchRow(DB_FETCHMODE_ASSOC)) {
181 $columnNames[] = $row['Field'];
182 }
183 }
184
185 $showColNames = TRUE;
186 if ($dataSource == 'CRM_Import_DataSource_CSV' && !$skipColumnHeader) {
187 $showColNames = FALSE;
188 }
189 $this->assign('showColNames', $showColNames);
190
191 $this->_columnCount = count($columnNames);
192 $this->_columnNames = $columnNames;
193 $this->assign('columnNames', $columnNames);
194 //$this->_columnCount = $this->get( 'columnCount' );
195 $this->assign('columnCount', $this->_columnCount);
196 $this->_dataValues = $this->get('dataValues');
197 $this->assign('dataValues', $this->_dataValues);
198 $this->assign('rowDisplayCount', 2);
199 }
200
201 /**
202 * Function to actually build the form
203 *
204 * @return void
205 * @access public
206 */
207 public function buildQuickForm() {
208 //to save the current mappings
209 if (!$this->get('savedMapping')) {
210 $saveDetailsName = ts('Save this field mapping');
211 $this->applyFilter('saveMappingName', 'trim');
212 $this->add('text', 'saveMappingName', ts('Name'));
213 $this->add('text', 'saveMappingDesc', ts('Description'));
214 }
215 else {
216 $savedMapping = $this->get('savedMapping');
217
218 list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingImProvider, $mappingRelation, $mappingOperator, $mappingValue, $mappingWebsiteType) = CRM_Core_BAO_Mapping::getMappingFields($savedMapping);
219
220 //get loaded Mapping Fields
221 $mappingName = CRM_Utils_Array::value(1, $mappingName);
222 $mappingContactType = CRM_Utils_Array::value(1, $mappingContactType);
223 $mappingLocation = CRM_Utils_Array::value(1, $mappingLocation);
224 $mappingPhoneType = CRM_Utils_Array::value(1, $mappingPhoneType);
225 $mappingImProvider = CRM_Utils_Array::value(1, $mappingImProvider);
226 $mappingRelation = CRM_Utils_Array::value(1, $mappingRelation);
227 $mappingWebsiteType = CRM_Utils_Array::value(1, $mappingWebsiteType);
228
229 $this->assign('loadedMapping', $savedMapping);
230 $this->set('loadedMapping', $savedMapping);
231
232 $params = array('id' => $savedMapping);
233 $temp = array();
234 $mappingDetails = CRM_Core_BAO_Mapping::retrieve($params, $temp);
235
236 $this->assign('savedName', $mappingDetails->name);
237
238 $this->add('hidden', 'mappingId', $savedMapping);
239
240 $this->addElement('checkbox', 'updateMapping', ts('Update this field mapping'), NULL);
241 $saveDetailsName = ts('Save as a new field mapping');
242 $this->add('text', 'saveMappingName', ts('Name'));
243 $this->add('text', 'saveMappingDesc', ts('Description'));
244 }
245
246 $this->addElement('checkbox', 'saveMapping', $saveDetailsName, NULL, array('onclick' => "showSaveDetails(this)"));
247
248 $this->addFormRule(array('CRM_Contact_Import_Form_MapField', 'formRule'));
249
250 //-------- end of saved mapping stuff ---------
251
252 $defaults = array();
253 $mapperKeys = array_keys($this->_mapperFields);
254 $hasColumnNames = !empty($this->_columnNames);
255 $columnPatterns = $this->get('columnPatterns');
256 $dataPatterns = $this->get('dataPatterns');
257 $hasLocationTypes = $this->get('fieldTypes');
258
259 $this->_location_types = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
260
261 $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
262
263 // Pass default location to js
264 if ($defaultLocationType) {
265 $this->assign('defaultLocationType', $defaultLocationType->id);
266 $this->assign('defaultLocationTypeLabel', $this->_location_types[$defaultLocationType->id]);
267 }
268
269 /* Initialize all field usages to false */
270 foreach ($mapperKeys as $key) {
271 $this->_fieldUsed[$key] = FALSE;
272 }
273
274 $sel1 = $this->_mapperFields;
275 $sel2[''] = NULL;
276
277 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
278 $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
279 $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
280
281 foreach ($this->_location_types as $key => $value) {
282 $sel3['phone'][$key] = &$phoneTypes;
283 //build array for IM service provider type for contact
284 $sel3['im'][$key] = &$imProviders;
285 }
286
287 $sel4 = NULL;
288
289 // store and cache all relationship types
290 $contactRelation = new CRM_Contact_DAO_RelationshipType();
291 $contactRelation->find();
292 while ($contactRelation->fetch()) {
293 $contactRelationCache[$contactRelation->id] = array();
294 $contactRelationCache[$contactRelation->id]['contact_type_a'] = $contactRelation->contact_type_a;
295 $contactRelationCache[$contactRelation->id]['contact_sub_type_a'] = $contactRelation->contact_sub_type_a;
296 $contactRelationCache[$contactRelation->id]['contact_type_b'] = $contactRelation->contact_type_b;
297 $contactRelationCache[$contactRelation->id]['contact_sub_type_b'] = $contactRelation->contact_sub_type_b;
298 }
299 $highlightedFields = $highlightedRelFields = array();
300
301 $highlightedFields['email'] = 'All';
302 $highlightedFields['external_identifier'] = 'All';
303 $highlightedFields['first_name'] = 'Individual';
304 $highlightedFields['last_name'] = 'Individual';
305 $highlightedFields['household_name'] = 'Household';
306 $highlightedFields['organization_name'] = 'Organization';
307
308 foreach ($mapperKeys as $key) {
309 // check if there is a _a_b or _b_a in the key
310 if (strpos($key, '_a_b') || strpos($key, '_b_a')) {
311 list($id, $first, $second) = explode('_', $key);
312 }
313 else {
314 $id = $first = $second = NULL;
315 }
316 if (($first == 'a' && $second == 'b') || ($first == 'b' && $second == 'a')) {
317 $cType = $contactRelationCache[$id]["contact_type_{$second}"];
318
319 //CRM-5125 for contact subtype specific relationshiptypes
320 $cSubType = NULL;
321 if (CRM_Utils_Array::value("contact_sub_type_{$second}", $contactRelationCache[$id])) {
322 $cSubType = $contactRelationCache[$id]["contact_sub_type_{$second}"];
323 }
324
325 if (!$cType) {
326 $cType = 'All';
327 }
328
329 $relatedFields = array();
330 $relatedFields = CRM_Contact_BAO_Contact::importableFields($cType);
331 unset($relatedFields['']);
332 $values = array();
333 foreach ($relatedFields as $name => $field) {
334 $values[$name] = $field['title'];
335 if (isset($hasLocationTypes[$name])) {
336 $sel3[$key][$name] = $this->_location_types;
337 }
338 elseif ($name == 'url') {
339 $sel3[$key][$name] = $websiteTypes;
340 }
341 else {
342 $sel3[$name] = NULL;
343 }
344 }
345
346 //fix to append custom group name to field name, CRM-2676
347 if (!CRM_Utils_Array::value($cType, $this->_formattedFieldNames) || $cType == $this->_contactType) {
348 $this->_formattedFieldNames[$cType] = $this->formatCustomFieldName($values);
349 }
350
351 $this->_formattedFieldNames[$cType] = array_merge($values, $this->_formattedFieldNames[$cType]);
352
353 //Modified the Relationship fields if the fields are
354 //present in dedupe rule
355 if ($this->_onDuplicate != CRM_Import_Parser::DUPLICATE_NOCHECK &&
356 CRM_Utils_Array::value($cType, $this->_dedupeFields) &&
357 is_array($this->_dedupeFields[$cType])
358 ) {
359 static $cTypeArray = array();
360 if ($cType != $this->_contactType && !in_array($cType, $cTypeArray)) {
361 foreach ($this->_dedupeFields[$cType] as $val) {
362 if ($valTitle = CRM_Utils_Array::value($val, $this->_formattedFieldNames[$cType])) {
363 $this->_formattedFieldNames[$cType][$val] = $valTitle . ' (match to contact)';
364 }
365 }
366 $cTypeArray[] = $cType;
367 }
368 }
369
370 foreach ($highlightedFields as $k => $v) {
371 if ($v == $cType || $v == 'All') {
372 $highlightedRelFields[$key][] = $k;
373 }
374 }
375 $this->assign('highlightedRelFields', $highlightedRelFields);
376 $sel2[$key] = $this->_formattedFieldNames[$cType];
377
378 if (!empty($cSubType)) {
379 //custom fields for sub type
380 $subTypeFields = CRM_Core_BAO_CustomField::getFieldsForImport($cSubType);
381
382 if (!empty($subTypeFields)) {
383 $subType = NULL;
384 foreach ($subTypeFields as $customSubTypeField => $details) {
385 $subType[$customSubTypeField] = $details['title'];
386 $sel2[$key] = array_merge($sel2[$key], $this->formatCustomFieldName($subType));
387 }
388 }
389 }
390
391 foreach ($this->_location_types as $k => $value) {
392 $sel4[$key]['phone'][$k] = &$phoneTypes;
393 //build array of IM service provider for related contact
394 $sel4[$key]['im'][$k] = &$imProviders;
395 }
396 }
397 else {
398 $options = NULL;
399 if (!empty($hasLocationTypes[$key])) {
400 $options = $this->_location_types;
401 }
402 elseif ($key == 'url') {
403 $options = $websiteTypes;
404 }
405 $sel2[$key] = $options;
406 }
407 }
408
409 $js = "<script type='text/javascript'>\n";
410 $formName = 'document.forms.' . $this->_name;
411 //used to warn for mismatch column count or mismatch mapping
412 $warning = 0;
413 for ($i = 0; $i < $this->_columnCount; $i++) {
414 $sel = &$this->addElement('hierselect', "mapper[$i]", ts('Mapper for Field %1', array(1 => $i)), NULL);
415 $jsSet = FALSE;
416 if ($this->get('savedMapping')) {
417 if (isset($mappingName[$i])) {
418 if ($mappingName[$i] != ts('- do not import -')) {
419
420 if (isset($mappingRelation[$i])) {
421 // relationship mapping
422 switch ($this->get('contactType')) {
423 case CRM_Import_Parser::CONTACT_INDIVIDUAL:
424 $contactType = 'Individual';
425 break;
426
427 case CRM_Import_Parser::CONTACT_HOUSEHOLD:
428 $contactType = 'Household';
429 break;
430
431 case CRM_Import_Parser::CONTACT_ORGANIZATION:
432 $contactType = 'Organization';
433 }
434 //CRM-5125
435 $contactSubType = NULL;
436 if ($this->get('contactSubType')) {
437 $contactSubType = $this->get('contactSubType');
438 }
439
440 $relations = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, NULL, NULL, $contactType,
441 FALSE, 'label', TRUE, $contactSubType
442 );
443
444 foreach ($relations as $key => $var) {
445 if ($key == $mappingRelation[$i]) {
446 $relation = $key;
447 break;
448 }
449 }
450
451 $contactDetails = strtolower(str_replace(" ", "_", $mappingName[$i]));
452 $websiteTypeId = isset($mappingWebsiteType[$i]) ? $mappingWebsiteType[$i] : NULL;
453 $locationId = isset($mappingLocation[$i]) ? $mappingLocation[$i] : 0;
454 $phoneType = isset($mappingPhoneType[$i]) ? $mappingPhoneType[$i] : NULL;
455 //get provider id from saved mappings
456 $imProvider = isset($mappingImProvider[$i]) ? $mappingImProvider[$i] : NULL;
457
458 if ($websiteTypeId) {
459 $defaults["mapper[$i]"] = array($relation, $contactDetails, $websiteTypeId);
460 if (!$websiteTypeId) {
461 $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
462 }
463 }
464 else {
465 // default for IM/phone when mapping with relation is true
466 $typeId = NULL;
467 if (isset($phoneType)) {
468 $typeId = $phoneType;
469 }
470 elseif (isset($imProvider)) {
471 $typeId = $imProvider;
472 }
473 $defaults["mapper[$i]"] = array($relation, $contactDetails, $locationId, $typeId);
474 if (!$locationId) {
475 $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
476 }
477 }
478 // fix for edge cases, CRM-4954
479 if ($contactDetails == 'image_url') {
480 $contactDetails = str_replace('url', 'URL', $contactDetails);
481 }
482
483 if (!$contactDetails) {
484 $js .= "{$formName}['mapper[$i][1]'].style.display = 'none';\n";
485 }
486
487 if ((!$phoneType) && (!$imProvider)) {
488 $js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
489 }
490 //$js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
491 $jsSet = TRUE;
492 }
493 else {
494 $mappingHeader = array_keys($this->_mapperFields, $mappingName[$i]);
495 $websiteTypeId = isset($mappingWebsiteType[$i]) ? $mappingWebsiteType[$i] : NULL;
496 $locationId = isset($mappingLocation[$i]) ? $mappingLocation[$i] : 0;
497 $phoneType = isset($mappingPhoneType[$i]) ? $mappingPhoneType[$i] : NULL;
498 // get IM service provider id
499 $imProvider = isset($mappingImProvider[$i]) ? $mappingImProvider[$i] : NULL;
500
501 if ($websiteTypeId) {
502 if (!$websiteTypeId) {
503 $js .= "{$formName}['mapper[$i][1]'].style.display = 'none';\n";
504 }
505 $defaults["mapper[$i]"] = array($mappingHeader[0], $websiteTypeId);
506 }
507 else {
508 if (!$locationId) {
509 $js .= "{$formName}['mapper[$i][1]'].style.display = 'none';\n";
510 }
511 //default for IM/phone without related contact
512 $typeId = NULL;
513 if (isset($phoneType)) {
514 $typeId = $phoneType;
515 }
516 elseif (isset($imProvider)) {
517 $typeId = $imProvider;
518 }
519 $defaults["mapper[$i]"] = array($mappingHeader[0], $locationId, $typeId);
520 }
521
522 if ((!$phoneType) && (!$imProvider)) {
523 $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
524 }
525
526 $js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
527
528 $jsSet = TRUE;
529 }
530 }
531 else {
532 $defaults["mapper[$i]"] = array();
533 }
534 if (!$jsSet) {
535 for ($k = 1; $k < 4; $k++) {
536 $js .= "{$formName}['mapper[$i][$k]'].style.display = 'none';\n";
537 }
538 }
539 }
540 else {
541 // this load section to help mapping if we ran out of saved columns when doing Load Mapping
542 $js .= "swapOptions($formName, 'mapper[$i]', 0, 3, 'hs_mapper_0_');\n";
543
544 if ($hasColumnNames) {
545 $defaults["mapper[$i]"] = array($this->defaultFromColumnName($this->_columnNames[$i], $columnPatterns));
546 }
547 else {
548 $defaults["mapper[$i]"] = array($this->defaultFromData($dataPatterns, $i));
549 }
550 }
551 //end of load mapping
552 }
553 else {
554 $js .= "swapOptions($formName, 'mapper[$i]', 0, 3, 'hs_mapper_0_');\n";
555 if ($hasColumnNames) {
556 // do array search first to see if has mapped key
557 $columnKey = '';
558 $columnKey = array_search($this->_columnNames[$i], $this->_mapperFields);
559 if (isset($this->_fieldUsed[$columnKey])) {
560 $defaults["mapper[$i]"] = $columnKey;
561 $this->_fieldUsed[$key] = TRUE;
562 }
563 else {
564 // Infer the default from the column names if we have them
565 $defaults["mapper[$i]"] = array(
566 $this->defaultFromColumnName($this->_columnNames[$i],
567 $columnPatterns
568 ),
569 0,
570 );
571 }
572 }
573 else {
574 // Otherwise guess the default from the form of the data
575 $defaults["mapper[$i]"] = array(
576 $this->defaultFromData($dataPatterns, $i),
577 // $defaultLocationType->id
578 0,
579 );
580 }
581 }
582 $sel->setOptions(array($sel1, $sel2, $sel3, $sel4));
583 }
584
585 $js .= "</script>\n";
586 $this->assign('initHideBoxes', $js);
587
588 //set warning if mismatch in more than
589 if (isset($mappingName) &&
590 ($this->_columnCount != count($mappingName))
591 ) {
592 $warning++;
593 }
594
595 if ($warning != 0 && $this->get('savedMapping')) {
596 $session = CRM_Core_Session::singleton();
597 $session->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.'));
598 }
599 else {
600 $session = CRM_Core_Session::singleton();
601 $session->setStatus(NULL);
602 }
603
604 $this->setDefaults($defaults);
605
606 $this->addButtons(array(
607 array(
608 'type' => 'back',
609 'name' => ts('<< Previous'),
610 ),
611 array(
612 'type' => 'next',
613 'name' => ts('Continue >>'),
614 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
615 'isDefault' => TRUE,
616 ),
617 array(
618 'type' => 'cancel',
619 'name' => ts('Cancel'),
620 ),
621 )
622 );
623 }
624
625 /**
626 * global validation rules for the form
627 *
628 * @param array $fields posted values of the form
629 *
630 * @return array list of errors to be posted back to the form
631 * @static
632 * @access public
633 */
634 static function formRule($fields) {
635 $errors = array();
636 if (CRM_Utils_Array::value('saveMapping', $fields)) {
637 $nameField = CRM_Utils_Array::value('saveMappingName', $fields);
638 if (empty($nameField)) {
639 $errors['saveMappingName'] = ts('Name is required to save Import Mapping');
640 }
641 else {
642 $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Contact', 'name');
643 if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) {
644 $errors['saveMappingName'] = ts('Duplicate Import Mapping Name');
645 }
646 }
647 }
648 $template = CRM_Core_Smarty::singleton();
649 if (CRM_Utils_Array::value('saveMapping', $fields)) {
650 $template->assign('isCheked', TRUE);
651 }
652
653 if (!empty($errors)) {
654 $_flag = 1;
655 $assignError = new CRM_Core_Page();
656 $assignError->assign('mappingDetailsError', $_flag);
657 return $errors;
658 }
659 else {
660 return TRUE;
661 }
662 }
663
664 /**
665 * Process the mapped fields and map it into the uploaded file
666 * preview the file and extract some summary statistics
667 *
668 * @return void
669 * @access public
670 */
671 public function postProcess() {
672 $params = $this->controller->exportValues('MapField');
673
674 //reload the mapfield if load mapping is pressed
675 if (!empty($params['savedMapping'])) {
676 $this->set('savedMapping', $params['savedMapping']);
677 $this->controller->resetPage($this->_name);
678 return;
679 }
680
681 $mapper = array();
682 $mapperKeys = array();
683 $mapperKeys = $this->controller->exportValue($this->_name, 'mapper');
684 $mapperKeysMain = array();
685
686 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
687 $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
688 $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
689 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
690
691 //these mapper params need to set key as array and val as null.
692 $mapperParams = array(
693 'related' => 'relatedVal',
694 'locations' => 'locationsVal',
695 'mapperLocType' => 'mapperLocTypeVal',
696 'mapperPhoneType' => 'mapperPhoneTypeVal',
697 'mapperImProvider' => 'mapperImProviderVal',
698 'mapperWebsiteType' => 'mapperWebsiteTypeVal',
699 'relatedContactType' => 'relatedContactTypeVal',
700 'relatedContactDetails' => 'relatedContactDetailsVal',
701 'relatedContactLocType' => 'relatedContactLocTypeVal',
702 'relatedContactPhoneType' => 'relatedContactPhoneTypeVal',
703 'relatedContactImProvider' => 'relatedContactImProviderVal',
704 'relatedContactWebsiteType' => 'relatedContactWebsiteTypeVal',
705 );
706
707 //set respective mapper params to array.
708 foreach (array_keys($mapperParams) as $mapperParam)$$mapperParam = array();
709
710 for ($i = 0; $i < $this->_columnCount; $i++) {
711 //set respective mapper value to null
712 foreach (array_values($mapperParams) as $mapperParam)$$mapperParam = NULL;
713
714 $fldName = CRM_Utils_Array::value(0, $mapperKeys[$i]);
715 $selOne = CRM_Utils_Array::value(1, $mapperKeys[$i]);
716 $selTwo = CRM_Utils_Array::value(2, $mapperKeys[$i]);
717 $selThree = CRM_Utils_Array::value(3, $mapperKeys[$i]);
718 $mapper[$i] = $this->_mapperFields[$mapperKeys[$i][0]];
719 $mapperKeysMain[$i] = $fldName;
720
721 //need to differentiate non location elements.
722 if ($selOne && is_numeric($selOne)) {
723 if ($fldName == 'url') {
724 $mapperWebsiteTypeVal = $websiteTypes[$selOne];
725 }
726 else {
727 $locationsVal = $locationTypes[$selOne];
728 $mapperLocTypeVal = $selOne;
729 if ($selTwo && is_numeric($selTwo)) {
730 if ($fldName == 'phone') {
731 $mapperPhoneTypeVal = $phoneTypes[$selTwo];
732 }
733 elseif ($fldName == 'im') {
734 $mapperImProviderVal = $imProviders[$selTwo];
735 }
736 }
737 }
738 }
739
740 //relationship contact mapper info.
741 list($id, $first, $second) = CRM_Utils_System::explode('_', $fldName, 3);
742 if (($first == 'a' && $second == 'b') ||
743 ($first == 'b' && $second == 'a')
744 ) {
745 $relatedVal = $this->_mapperFields[$fldName];
746 if ($selOne) {
747 if ($selOne == 'url') {
748 $relatedContactWebsiteTypeVal = $websiteTypes[$selTwo];
749 }
750 else {
751 $relatedContactLocTypeVal = CRM_Utils_Array::value($selTwo, $locationTypes);
752 if ($selThree) {
753 if ($selOne == 'phone') {
754 $relatedContactPhoneTypeVal = $phoneTypes[$selThree];
755 }
756 elseif ($selOne == 'im') {
757 $relatedContactImProviderVal = $imProviders[$selThree];
758 }
759 }
760 }
761
762 //get the related contact type.
763 $relationType = new CRM_Contact_DAO_RelationshipType();
764 $relationType->id = $id;
765 $relationType->find(TRUE);
766 $relatedContactTypeVal = $relationType->{"contact_type_$second"};
767 $relatedContactDetailsVal = $this->_formattedFieldNames[$relatedContactTypeVal][$selOne];
768 }
769 }
770
771 //set the respective mapper param array values.
772 foreach ($mapperParams as $mapperParamKey => $mapperParamVal) {
773 ${$mapperParamKey}[$i] = $$mapperParamVal;
774 }
775 }
776
777 $this->set('columnNames', $this->_columnNames);
778
779 //set main contact properties.
780 $properties = array(
781 'ims' => 'mapperImProvider',
782 'mapper' => 'mapper',
783 'phones' => 'mapperPhoneType',
784 'websites' => 'mapperWebsiteType',
785 'locations' => 'locations',
786 );
787 foreach ($properties as $propertyName => $propertyVal) {
788 $this->set($propertyName, $$propertyVal);
789 }
790
791 //set related contact propeties.
792 $relProperties = array(
793 'related', 'relatedContactType', 'relatedContactDetails',
794 'relatedContactLocType', 'relatedContactPhoneType', 'relatedContactImProvider',
795 'relatedContactWebsiteType',
796 );
797 foreach ($relProperties as $relProperty) {
798 $this->set($relProperty, $$relProperty);
799 }
800
801 // store mapping Id to display it in the preview page
802 $this->set('loadMappingId', CRM_Utils_Array::value('mappingId', $params));
803
804 //Updating Mapping Records
805 if (CRM_Utils_Array::value('updateMapping', $params)) {
806
807 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
808
809 $mappingFields = new CRM_Core_DAO_MappingField();
810 $mappingFields->mapping_id = $params['mappingId'];
811 $mappingFields->find();
812
813 $mappingFieldsId = array();
814 while ($mappingFields->fetch()) {
815 if ($mappingFields->id) {
816 $mappingFieldsId[$mappingFields->column_number] = $mappingFields->id;
817 }
818 }
819
820 for ($i = 0; $i < $this->_columnCount; $i++) {
821 $updateMappingFields = new CRM_Core_DAO_MappingField();
822 $updateMappingFields->id = CRM_Utils_Array::value($i,$mappingFieldsId);
823 $updateMappingFields->mapping_id = $params['mappingId'];
824 $updateMappingFields->column_number = $i;
825
826 $mapperKeyParts = explode('_', $mapperKeys[$i][0], 3);
827 $id = isset($mapperKeyParts[0]) ? $mapperKeyParts[0] : NULL;
828 $first = isset($mapperKeyParts[1]) ? $mapperKeyParts[1] : NULL;
829 $second = isset($mapperKeyParts[2]) ? $mapperKeyParts[2] : NULL;
830 if (($first == 'a' && $second == 'b') || ($first == 'b' && $second == 'a')) {
831 $updateMappingFields->relationship_type_id = $id;
832 $updateMappingFields->relationship_direction = "{$first}_{$second}";
833 $updateMappingFields->name = ucwords(str_replace("_", " ", $mapperKeys[$i][1]));
834 // get phoneType id and provider id separately
835 // before updating mappingFields of phone and IM for related contact, CRM-3140
836 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'url') {
837 $updateMappingFields->website_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
838 }
839 else {
840 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'phone') {
841 $updateMappingFields->phone_type_id = isset($mapperKeys[$i][3]) ? $mapperKeys[$i][3] : NULL;
842 }
843 elseif (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'im') {
844 $updateMappingFields->im_provider_id = isset($mapperKeys[$i][3]) ? $mapperKeys[$i][3] : NULL;
845 }
846 $updateMappingFields->location_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
847 }
848 }
849 else {
850 $updateMappingFields->name = $mapper[$i];
851 $updateMappingFields->relationship_type_id = 'NULL';
852 $updateMappingFields->relationship_type_direction = 'NULL';
853 // to store phoneType id and provider id seperately
854 // before updating mappingFields for phone and IM, CRM-3140
855 if (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'url') {
856 $updateMappingFields->website_type_id = isset($mapperKeys[$i][1]) ? $mapperKeys[$i][1] : NULL;
857 }
858 else {
859 if (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'phone') {
860 $updateMappingFields->phone_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
861 }
862 elseif (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'im') {
863 $updateMappingFields->im_provider_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
864 }
865 $location = array_keys($locationTypes, $locations[$i]);
866 $updateMappingFields->location_type_id = (isset($location) && isset($location[0])) ? $location[0] : NULL;
867 }
868 }
869 $updateMappingFields->save();
870 }
871 }
872
873 //Saving Mapping Details and Records
874 if (CRM_Utils_Array::value('saveMapping', $params)) {
875 $mappingParams = array(
876 'name' => $params['saveMappingName'],
877 'description' => $params['saveMappingDesc'],
878 'mapping_type_id' => CRM_Core_OptionGroup::getValue('mapping_type',
879 'Import Contact',
880 'name'
881 ),
882 );
883
884 $saveMapping = CRM_Core_BAO_Mapping::add($mappingParams);
885
886 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
887 $contactType = $this->get('contactType');
888 switch ($contactType) {
889 case CRM_Import_Parser::CONTACT_INDIVIDUAL:
890 $cType = 'Individual';
891 break;
892
893 case CRM_Import_Parser::CONTACT_HOUSEHOLD:
894 $cType = 'Household';
895 break;
896
897 case CRM_Import_Parser::CONTACT_ORGANIZATION:
898 $cType = 'Organization';
899 }
900
901 for ($i = 0; $i < $this->_columnCount; $i++) {
902 $saveMappingFields = new CRM_Core_DAO_MappingField();
903 $saveMappingFields->mapping_id = $saveMapping->id;
904 $saveMappingFields->contact_type = $cType;
905 $saveMappingFields->column_number = $i;
906
907 $mapperKeyParts = explode('_', $mapperKeys[$i][0], 3);
908 $id = isset($mapperKeyParts[0]) ? $mapperKeyParts[0] : NULL;
909 $first = isset($mapperKeyParts[1]) ? $mapperKeyParts[1] : NULL;
910 $second = isset($mapperKeyParts[2]) ? $mapperKeyParts[2] : NULL;
911 if (($first == 'a' && $second == 'b') || ($first == 'b' && $second == 'a')) {
912 $saveMappingFields->name = ucwords(str_replace("_", " ", $mapperKeys[$i][1]));
913 $saveMappingFields->relationship_type_id = $id;
914 $saveMappingFields->relationship_direction = "{$first}_{$second}";
915 // to get phoneType id and provider id seperately
916 // before saving mappingFields of phone and IM for related contact, CRM-3140
917 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'url') {
918 $saveMappingFields->website_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
919 }
920 else {
921 if (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'phone') {
922 $saveMappingFields->phone_type_id = isset($mapperKeys[$i][3]) ? $mapperKeys[$i][3] : NULL;
923 }
924 elseif (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'im') {
925 $saveMappingFields->im_provider_id = isset($mapperKeys[$i][3]) ? $mapperKeys[$i][3] : NULL;
926 }
927 $saveMappingFields->location_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
928 }
929 }
930 else {
931 $saveMappingFields->name = $mapper[$i];
932 $location_id = array_keys($locationTypes, $locations[$i]);
933 // to get phoneType id and provider id seperately
934 // before saving mappingFields of phone and IM, CRM-3140
935 if (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'url') {
936 $saveMappingFields->website_type_id = isset($mapperKeys[$i][1]) ? $mapperKeys[$i][1] : NULL;
937 }
938 else {
939 if (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'phone') {
940 $saveMappingFields->phone_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
941 }
942 elseif (CRM_Utils_Array::value('0', $mapperKeys[$i]) == 'im') {
943 $saveMappingFields->im_provider_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
944 }
945 $saveMappingFields->location_type_id = isset($location_id[0]) ? $location_id[0] : NULL;
946 }
947 $saveMappingFields->relationship_type_id = NULL;
948 }
949 $saveMappingFields->save();
950 }
951 $this->set('savedMapping', $saveMappingFields->mapping_id);
952 }
953
954 $parser = new CRM_Contact_Import_Parser_Contact($mapperKeysMain, $mapperLocType, $mapperPhoneType,
955 $mapperImProvider, $related, $relatedContactType,
956 $relatedContactDetails, $relatedContactLocType,
957 $relatedContactPhoneType, $relatedContactImProvider,
958 $mapperWebsiteType, $relatedContactWebsiteType
959 );
960
961 $primaryKeyName = $this->get('primaryKeyName');
962 $statusFieldName = $this->get('statusFieldName');
963 $parser->run($this->_importTableName,
964 $mapper,
965 CRM_Import_Parser::MODE_PREVIEW,
966 $this->get('contactType'),
967 $primaryKeyName,
968 $statusFieldName,
969 $this->_onDuplicate,
970 NULL, NULL, FALSE,
971 CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
972 $this->get('contactSubType'),
973 $this->get('dedupe')
974 );
975
976 // add all the necessary variables to the form
977 $parser->set($this);
978 }
979
980 /**
981 * format custom field name.
982 * combine group and field name to avoid conflict.
983 *
984 * @return void
985 * @access public
986 */
987 function formatCustomFieldName(&$fields) {
988 //CRM-2676, replacing the conflict for same custom field name from different custom group.
989 $fieldIds = $formattedFieldNames = array();
990 foreach ($fields as $key => $value) {
991 if ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($key)) {
992 $fieldIds[] = $customFieldId;
993 }
994 }
995
996 if (!empty($fieldIds) && is_array($fieldIds)) {
997 $groupTitles = CRM_Core_BAO_CustomGroup::getGroupTitles($fieldIds);
998
999 if (!empty($groupTitles)) {
1000 foreach ($groupTitles as $fId => $values) {
1001 $key = "custom_{$fId}";
1002 $groupTitle = $values['groupTitle'];
1003 $formattedFieldNames[$key] = $fields[$key] . ' :: ' . $groupTitle;
1004 }
1005 }
1006 }
1007
1008 return $formattedFieldNames;
1009 }
1010 }
1011