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