3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2013
38 abstract class CRM_Import_Parser
{
39 CONST MAX_ERRORS
= 250, MAX_WARNINGS
= 25, VALID
= 1, WARNING
= 2, ERROR
= 4, CONFLICT
= 8, STOP
= 16, DUPLICATE
= 32, MULTIPLE_DUPE
= 64, NO_MATCH
= 128, UNPARSED_ADDRESS_WARNING
= 256;
42 * various parser modes
44 CONST MODE_MAPFIELD
= 1, MODE_PREVIEW
= 2, MODE_SUMMARY
= 4, MODE_IMPORT
= 8;
47 * codes for duplicate record handling
49 CONST DUPLICATE_SKIP
= 1, DUPLICATE_REPLACE
= 2, DUPLICATE_UPDATE
= 4, DUPLICATE_FILL
= 8, DUPLICATE_NOCHECK
= 16;
52 * various Contact types
54 CONST CONTACT_INDIVIDUAL
= 1, CONTACT_HOUSEHOLD
= 2, CONTACT_ORGANIZATION
= 4;
55 CONST DEFAULT_TIMEOUT
= 30;
57 protected $_tableName;
65 * total number of lines in file
70 * total number of non empty lines
72 protected $_totalCount;
75 * running total number of valid lines
77 protected $_validCount;
80 * running total number of invalid rows
82 protected $_invalidRowCount;
85 * maximum number of invalid rows to store
87 protected $_maxErrorCount;
90 * array of error lines, bounded by MAX_ERROR
95 * total number of conflict lines
97 protected $_conflictCount;
100 * array of conflict lines
102 protected $_conflicts;
105 * total number of duplicate (from database) lines
107 protected $_duplicateCount;
110 * array of duplicate lines
112 protected $_duplicates;
115 * running total number of warnings
117 protected $_warningCount;
120 * running total number of un matched Conact
122 protected $_unMatchCount;
125 * array of unmatched lines
130 * maximum number of warnings to store
132 protected $_maxWarningCount = self
::MAX_WARNINGS
;
135 * total number of contacts with unparsed addresses
137 protected $_unparsedAddressCount;
140 * array of warning lines, bounded by MAX_WARNING
142 protected $_warnings;
145 * array of all the fields that could potentially be part
146 * of this import process
152 * array of the fields that are actually part of the import process
153 * the position in the array also dictates their position in the import
157 protected $_activeFields;
160 * cache the count of active fields
164 protected $_activeFieldCount;
167 * maximum number of non-empty/comment lines to process
171 protected $_maxLinesToProcess;
174 * cache of preview rows
181 * filename of error data
185 protected $_errorFileName;
188 * filename of conflict data
192 protected $_conflictFileName;
195 * filename of duplicate data
199 protected $_duplicateFileName;
202 * filename of mismatch data
206 protected $_misMatchFilemName;
208 protected $_primaryKeyName;
209 protected $_statusFieldName;
217 public $_contactType;
224 public $_onDuplicate;
227 * dedupe rule group id to use if set
231 public $_dedupeRuleGroupID = NULL;
233 function __construct() {
234 $this->_maxLinesToProcess
= 0;
235 $this->_maxErrorCount
= self
::MAX_ERRORS
;
238 abstract function init();
240 function run($tableName,
242 $mode = self
::MODE_PREVIEW
,
243 $contactType = self
::CONTACT_INDIVIDUAL
,
244 $primaryKeyName = '_id',
245 $statusFieldName = '_status',
246 $onDuplicate = self
::DUPLICATE_SKIP
,
248 $totalRowCount = NULL,
249 $doGeocodeAddress = FALSE,
250 $timeout = CRM_Import_Parser
::DEFAULT_TIMEOUT
,
251 $contactSubType = NULL,
252 $dedupeRuleGroupID = NULL
255 // TODO: Make the timeout actually work
256 $this->_onDuplicate
= $onDuplicate;
257 $this->_dedupeRuleGroupID
= $dedupeRuleGroupID;
259 switch ($contactType) {
260 case CRM_Import_Parser
::CONTACT_INDIVIDUAL
:
261 $this->_contactType
= 'Individual';
264 case CRM_Import_Parser
::CONTACT_HOUSEHOLD
:
265 $this->_contactType
= 'Household';
268 case CRM_Import_Parser
::CONTACT_ORGANIZATION
:
269 $this->_contactType
= 'Organization';
272 $this->_contactSubType
= $contactSubType;
276 $this->_rowCount
= $this->_warningCount
= 0;
277 $this->_invalidRowCount
= $this->_validCount
= 0;
278 $this->_totalCount
= $this->_conflictCount
= 0;
280 $this->_errors
= array();
281 $this->_warnings
= array();
282 $this->_conflicts
= array();
283 $this->_unparsedAddresses
= array();
287 $this->_tableName
= $tableName;
288 $this->_primaryKeyName
= $primaryKeyName;
289 $this->_statusFieldName
= $statusFieldName;
291 if ($mode == self
::MODE_MAPFIELD
) {
292 $this->_rows
= array();
295 $this->_activeFieldCount
= count($this->_activeFields
);
298 if ($mode == self
::MODE_IMPORT
) {
299 //get the key of email field
300 foreach ($mapper as $key => $value) {
301 if (strtolower($value) == 'email') {
311 $config = CRM_Core_Config
::singleton();
312 $statusFile = "{$config->uploadDir}status_{$statusID}.txt";
313 $status = "<div class='description'> " . ts('No processing status reported yet.') . "</div>";
315 //do not force the browser to display the save dialog, CRM-7640
316 $contents = json_encode(array(0, $status));
318 file_put_contents($statusFile, $contents);
320 $startTimestamp = $currTimestamp = $prevTimestamp = time();
323 // get the contents of the temp. import table
324 $query = "SELECT * FROM $tableName";
325 if ($mode == self
::MODE_IMPORT
) {
326 $query .= " WHERE $statusFieldName = 'NEW'";
328 $dao = new CRM_Core_DAO();
329 $db = $dao->getDatabaseConnection();
330 $result = $db->query($query);
332 while ($values = $result->fetchRow(DB_FETCHMODE_ORDERED
)) {
335 /* trim whitespace around the values */
338 foreach ($values as $k => $v) {
339 $values[$k] = trim($v, " \t\r\n");
341 if (CRM_Utils_System
::isNull($values)) {
345 $this->_totalCount++
;
347 if ($mode == self
::MODE_MAPFIELD
) {
348 $returnCode = $this->mapField($values);
350 elseif ($mode == self
::MODE_PREVIEW
) {
351 $returnCode = $this->preview($values);
353 elseif ($mode == self
::MODE_SUMMARY
) {
354 $returnCode = $this->summary($values);
356 elseif ($mode == self
::MODE_IMPORT
) {
357 //print "Running parser in import mode<br/>\n";
358 $returnCode = $this->import($onDuplicate, $values, $doGeocodeAddress);
359 if ($statusID && (($this->_rowCount %
$skip) == 0)) {
360 $currTimestamp = time();
361 $totalTime = ($currTimestamp - $startTimestamp);
362 $time = ($currTimestamp - $prevTimestamp);
363 $recordsLeft = $totalRowCount - $this->_rowCount
;
364 if ($recordsLeft < 0) {
367 $estimatedTime = ($recordsLeft / $skip) * $time;
368 $estMinutes = floor($estimatedTime / 60);
370 if ($estMinutes > 1) {
371 $timeFormatted = $estMinutes . ' ' . ts('minutes') . ' ';
372 $estimatedTime = $estimatedTime - ($estMinutes * 60);
374 $timeFormatted .= round($estimatedTime) . ' ' . ts('seconds');
375 $processedPercent = (int )(($this->_rowCount
* 100) / $totalRowCount);
376 $statusMsg = ts('%1 of %2 records - %3 remaining',
377 array(1 => $this->_rowCount
, 2 => $totalRowCount, 3 => $timeFormatted)
380 <div class=\"description\">
381 <strong>{$statusMsg}</strong>
385 $contents = json_encode (array($processedPercent, $status));
387 file_put_contents($statusFile, $contents);
389 $prevTimestamp = $currTimestamp;
394 $returnCode = self
::ERROR
;
397 // note that a line could be valid but still produce a warning
398 if ($returnCode & self
::VALID
) {
399 $this->_validCount++
;
400 if ($mode == self
::MODE_MAPFIELD
) {
401 $this->_rows
[] = $values;
402 $this->_activeFieldCount
= max($this->_activeFieldCount
, count($values));
406 if ($returnCode & self
::WARNING
) {
407 $this->_warningCount++
;
408 if ($this->_warningCount
< $this->_maxWarningCount
) {
409 $this->_warningCount
[] = $line;
413 if ($returnCode & self
::ERROR
) {
414 $this->_invalidRowCount++
;
415 if ($this->_invalidRowCount
< $this->_maxErrorCount
) {
416 array_unshift($values, $this->_rowCount
);
417 $this->_errors
[] = $values;
421 if ($returnCode & self
::CONFLICT
) {
422 $this->_conflictCount++
;
423 array_unshift($values, $this->_rowCount
);
424 $this->_conflicts
[] = $values;
427 if ($returnCode & self
::NO_MATCH
) {
428 $this->_unMatchCount++
;
429 array_unshift($values, $this->_rowCount
);
430 $this->_unMatch
[] = $values;
433 if ($returnCode & self
::DUPLICATE
) {
434 if ($returnCode & self
::MULTIPLE_DUPE
) {
435 /* TODO: multi-dupes should be counted apart from singles
436 * on non-skip action */
438 $this->_duplicateCount++
;
439 array_unshift($values, $this->_rowCount
);
440 $this->_duplicates
[] = $values;
441 if ($onDuplicate != self
::DUPLICATE_SKIP
) {
442 $this->_validCount++
;
446 if ($returnCode & self
::UNPARSED_ADDRESS_WARNING
) {
447 $this->_unparsedAddressCount++
;
448 array_unshift($values, $this->_rowCount
);
449 $this->_unparsedAddresses
[] = $values;
451 // we give the derived class a way of aborting the process
452 // note that the return code could be multiple code or'ed together
453 if ($returnCode & self
::STOP
) {
457 // if we are done processing the maxNumber of lines, break
458 if ($this->_maxLinesToProcess
> 0 && $this->_validCount
>= $this->_maxLinesToProcess
) {
462 // clean up memory from dao's
463 CRM_Core_DAO
::freeResult();
465 // see if we've hit our timeout yet
466 /* if ( $the_thing_with_the_stuff ) {
472 if ($mode == self
::MODE_PREVIEW ||
$mode == self
::MODE_IMPORT
) {
473 $customHeaders = $mapper;
475 $customfields = CRM_Core_BAO_CustomField
::getFields($this->_contactType
);
476 foreach ($customHeaders as $key => $value) {
477 if ($id = CRM_Core_BAO_CustomField
::getKeyID($value)) {
478 $customHeaders[$key] = $customfields[$id][0];
482 if ($this->_invalidRowCount
) {
483 // removed view url for invlaid contacts
484 $headers = array_merge(array(ts('Line Number'),
489 $this->_errorFileName
= self
::errorFileName(self
::ERROR
);
490 self
::exportCSV($this->_errorFileName
, $headers, $this->_errors
);
492 if ($this->_conflictCount
) {
493 $headers = array_merge(array(ts('Line Number'),
498 $this->_conflictFileName
= self
::errorFileName(self
::CONFLICT
);
499 self
::exportCSV($this->_conflictFileName
, $headers, $this->_conflicts
);
501 if ($this->_duplicateCount
) {
502 $headers = array_merge(array(ts('Line Number'),
503 ts('View Contact URL'),
508 $this->_duplicateFileName
= self
::errorFileName(self
::DUPLICATE
);
509 self
::exportCSV($this->_duplicateFileName
, $headers, $this->_duplicates
);
511 if ($this->_unMatchCount
) {
512 $headers = array_merge(array(ts('Line Number'),
518 $this->_misMatchFilemName
= self
::errorFileName(self
::NO_MATCH
);
519 self
::exportCSV($this->_misMatchFilemName
, $headers, $this->_unMatch
);
521 if ($this->_unparsedAddressCount
) {
522 $headers = array_merge(array(ts('Line Number'),
523 ts('Contact Edit URL'),
527 $this->_errorFileName
= self
::errorFileName(self
::UNPARSED_ADDRESS_WARNING
);
528 self
::exportCSV($this->_errorFileName
, $headers, $this->_unparsedAddresses
);
531 //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
532 return $this->fini();
535 abstract function mapField(&$values);
536 abstract function preview(&$values);
537 abstract function summary(&$values);
538 abstract function import($onDuplicate, &$values);
540 abstract function fini();
543 * Given a list of the importable field keys that the user has selected
544 * set the active fields array to this list
546 * @param array mapped array of values
551 function setActiveFields($fieldKeys) {
552 $this->_activeFieldCount
= count($fieldKeys);
553 foreach ($fieldKeys as $key) {
554 if (empty($this->_fields
[$key])) {
555 $this->_activeFields
[] = new CRM_Import_Field('', ts('- do not import -'));
558 $this->_activeFields
[] = clone($this->_fields
[$key]);
563 function setActiveFieldValues($elements) {
564 $maxCount = count($elements) < $this->_activeFieldCount ?
count($elements) : $this->_activeFieldCount
;
565 for ($i = 0; $i < $maxCount; $i++
) {
566 $this->_activeFields
[$i]->setValue($elements[$i]);
569 // reset all the values that we did not have an equivalent import element
570 for (; $i < $this->_activeFieldCount
; $i++
) {
571 $this->_activeFields
[$i]->resetValue();
574 // now validate the fields and return false if error
575 $valid = self
::VALID
;
576 for ($i = 0; $i < $this->_activeFieldCount
; $i++
) {
577 if (!$this->_activeFields
[$i]->validate()) {
578 // no need to do any more validation
579 $valid = self
::ERROR
;
586 function setActiveFieldLocationTypes($elements) {
587 for ($i = 0; $i < count($elements); $i++
) {
588 $this->_activeFields
[$i]->_hasLocationType
= $elements[$i];
592 function setActiveFieldPhoneTypes($elements) {
593 for ($i = 0; $i < count($elements); $i++
) {
594 $this->_activeFields
[$i]->_phoneType
= $elements[$i];
598 function setActiveFieldWebsiteTypes($elements) {
599 for ($i = 0; $i < count($elements); $i++
) {
600 $this->_activeFields
[$i]->_websiteType
= $elements[$i];
605 * Function to set IM Service Provider type fields
607 * @param array $elements IM service provider type ids
612 function setActiveFieldImProviders($elements) {
613 for ($i = 0; $i < count($elements); $i++
) {
614 $this->_activeFields
[$i]->_imProvider
= $elements[$i];
618 function setActiveFieldRelated($elements) {
619 for ($i = 0; $i < count($elements); $i++
) {
620 $this->_activeFields
[$i]->_related
= $elements[$i];
624 function setActiveFieldRelatedContactType($elements) {
625 for ($i = 0; $i < count($elements); $i++
) {
626 $this->_activeFields
[$i]->_relatedContactType
= $elements[$i];
630 function setActiveFieldRelatedContactDetails($elements) {
631 for ($i = 0; $i < count($elements); $i++
) {
632 $this->_activeFields
[$i]->_relatedContactDetails
= $elements[$i];
636 function setActiveFieldRelatedContactLocType($elements) {
637 for ($i = 0; $i < count($elements); $i++
) {
638 $this->_activeFields
[$i]->_relatedContactLocType
= $elements[$i];
642 function setActiveFieldRelatedContactPhoneType($elements) {
643 for ($i = 0; $i < count($elements); $i++
) {
644 $this->_activeFields
[$i]->_relatedContactPhoneType
= $elements[$i];
648 function setActiveFieldRelatedContactWebsiteType($elements) {
649 for ($i = 0; $i < count($elements); $i++
) {
650 $this->_activeFields
[$i]->_relatedContactWebsiteType
= $elements[$i];
655 * Function to set IM Service Provider type fields for related contacts
657 * @param array $elements IM service provider type ids of related contact
662 function setActiveFieldRelatedContactImProvider($elements) {
663 for ($i = 0; $i < count($elements); $i++
) {
664 $this->_activeFields
[$i]->_relatedContactImProvider
= $elements[$i];
669 * function to format the field values for input to the api
671 * @return array (reference ) associative array of name/value pairs
674 function &getActiveFieldParams() {
677 //CRM_Core_Error::debug( 'Count', $this->_activeFieldCount );
678 for ($i = 0; $i < $this->_activeFieldCount
; $i++
) {
679 if ($this->_activeFields
[$i]->_name
== 'do_not_import') {
683 if (isset($this->_activeFields
[$i]->_value
)) {
684 if (isset($this->_activeFields
[$i]->_hasLocationType
)) {
685 if (!isset($params[$this->_activeFields
[$i]->_name
])) {
686 $params[$this->_activeFields
[$i]->_name
] = array();
690 $this->_activeFields
[$i]->_name
=>
691 $this->_activeFields
[$i]->_value
,
692 'location_type_id' =>
693 $this->_activeFields
[$i]->_hasLocationType
,
696 if (isset($this->_activeFields
[$i]->_phoneType
)) {
697 $value['phone_type_id'] = $this->_activeFields
[$i]->_phoneType
;
700 // get IM service Provider type id
701 if (isset($this->_activeFields
[$i]->_imProvider
)) {
702 $value['provider_id'] = $this->_activeFields
[$i]->_imProvider
;
705 $params[$this->_activeFields
[$i]->_name
][] = $value;
707 elseif (isset($this->_activeFields
[$i]->_websiteType
)) {
709 $this->_activeFields
[$i]->_name
=> $this->_activeFields
[$i]->_value
,
710 'website_type_id' => $this->_activeFields
[$i]->_websiteType
,
713 $params[$this->_activeFields
[$i]->_name
][] = $value;
716 if (!isset($params[$this->_activeFields
[$i]->_name
])) {
717 if (!isset($this->_activeFields
[$i]->_related
)) {
718 $params[$this->_activeFields
[$i]->_name
] = $this->_activeFields
[$i]->_value
;
722 //minor fix for CRM-4062
723 if (isset($this->_activeFields
[$i]->_related
)) {
724 if (!isset($params[$this->_activeFields
[$i]->_related
])) {
725 $params[$this->_activeFields
[$i]->_related
] = array();
728 if (!isset($params[$this->_activeFields
[$i]->_related
]['contact_type']) && !empty($this->_activeFields
[$i]->_relatedContactType
)) {
729 $params[$this->_activeFields
[$i]->_related
]['contact_type'] = $this->_activeFields
[$i]->_relatedContactType
;
732 if (isset($this->_activeFields
[$i]->_relatedContactLocType
) && !empty($this->_activeFields
[$i]->_value
)) {
733 if (!is_array($params[$this->_activeFields
[$i]->_related
][$this->_activeFields
[$i]->_relatedContactDetails
])) {
734 $params[$this->_activeFields
[$i]->_related
][$this->_activeFields
[$i]->_relatedContactDetails
] = array();
737 $this->_activeFields
[$i]->_relatedContactDetails
=> $this->_activeFields
[$i]->_value
,
738 'location_type_id' => $this->_activeFields
[$i]->_relatedContactLocType
,
741 if (isset($this->_activeFields
[$i]->_relatedContactPhoneType
)) {
742 $value['phone_type_id'] = $this->_activeFields
[$i]->_relatedContactPhoneType
;
745 // get IM service Provider type id for related contact
746 if (isset($this->_activeFields
[$i]->_relatedContactImProvider
)) {
747 $value['provider_id'] = $this->_activeFields
[$i]->_relatedContactImProvider
;
750 $params[$this->_activeFields
[$i]->_related
][$this->_activeFields
[$i]->_relatedContactDetails
][] = $value;
752 elseif (isset($this->_activeFields
[$i]->_relatedContactWebsiteType
)) {
753 $params[$this->_activeFields
[$i]->_related
][$this->_activeFields
[$i]->_relatedContactDetails
][] = array(
754 'url' => $this->_activeFields
[$i]->_value
,
755 'website_type_id' => $this->_activeFields
[$i]->_relatedContactWebsiteType
,
759 $params[$this->_activeFields
[$i]->_related
][$this->_activeFields
[$i]->_relatedContactDetails
] = $this->_activeFields
[$i]->_value
;
768 function getSelectValues() {
770 foreach ($this->_fields
as $name => $field) {
771 $values[$name] = $field->_title
;
776 function getSelectTypes() {
778 foreach ($this->_fields
as $name => $field) {
779 $values[$name] = $field->_hasLocationType
;
784 function getColumnPatterns() {
786 foreach ($this->_fields
as $name => $field) {
787 $values[$name] = $field->_columnPattern
;
792 function getDataPatterns() {
794 foreach ($this->_fields
as $name => $field) {
795 $values[$name] = $field->_dataPattern
;
800 function addField($name, $title, $type = CRM_Utils_Type
::T_INT
,
801 $headerPattern = '//', $dataPattern = '//',
802 $hasLocationType = FALSE
804 $this->_fields
[$name] = new CRM_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
806 $this->_fields
['doNotImport'] = new CRM_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
818 function setMaxLinesToProcess($max) {
819 $this->_maxLinesToProcess
= $max;
823 * Store parser values
825 * @param CRM_Core_Session $store
830 function set($store, $mode = self
::MODE_SUMMARY
) {
831 $store->set('rowCount', $this->_rowCount
);
832 $store->set('fields', $this->getSelectValues());
833 $store->set('fieldTypes', $this->getSelectTypes());
835 $store->set('columnPatterns', $this->getColumnPatterns());
836 $store->set('dataPatterns', $this->getDataPatterns());
837 $store->set('columnCount', $this->_activeFieldCount
);
839 $store->set('totalRowCount', $this->_totalCount
);
840 $store->set('validRowCount', $this->_validCount
);
841 $store->set('invalidRowCount', $this->_invalidRowCount
);
842 $store->set('conflictRowCount', $this->_conflictCount
);
843 $store->set('unMatchCount', $this->_unMatchCount
);
845 switch ($this->_contactType
) {
847 $store->set('contactType', CRM_Import_Parser
::CONTACT_INDIVIDUAL
);
851 $store->set('contactType', CRM_Import_Parser
::CONTACT_HOUSEHOLD
);
855 $store->set('contactType', CRM_Import_Parser
::CONTACT_ORGANIZATION
);
858 if ($this->_invalidRowCount
) {
859 $store->set('errorsFileName', $this->_errorFileName
);
861 if ($this->_conflictCount
) {
862 $store->set('conflictsFileName', $this->_conflictFileName
);
864 if (isset($this->_rows
) && !empty($this->_rows
)) {
865 $store->set('dataValues', $this->_rows
);
868 if ($this->_unMatchCount
) {
869 $store->set('mismatchFileName', $this->_misMatchFilemName
);
872 if ($mode == self
::MODE_IMPORT
) {
873 $store->set('duplicateRowCount', $this->_duplicateCount
);
874 $store->set('unparsedAddressCount', $this->_unparsedAddressCount
);
875 if ($this->_duplicateCount
) {
876 $store->set('duplicatesFileName', $this->_duplicateFileName
);
878 if ($this->_unparsedAddressCount
) {
879 $store->set('errorsFileName', $this->_errorFileName
);
882 //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
886 * Export data to a CSV file
888 * @param string $filename
889 * @param array $header
895 static function exportCSV($fileName, $header, $data) {
897 if (file_exists($fileName) && !is_writable($fileName)) {
898 CRM_Core_Error
::movedSiteError($fileName);
900 //hack to remove '_status', '_statusMsg' and '_id' from error file
901 $errorValues = array();
902 $dbRecordStatus = array('IMPORTED', 'ERROR', 'DUPLICATE', 'INVALID', 'NEW');
903 foreach ($data as $rowCount => $rowValues) {
905 foreach ($rowValues as $key => $val) {
906 if (in_array($val, $dbRecordStatus) && $count == (count($rowValues) - 3)) {
909 $errorValues[$rowCount][$key] = $val;
913 $data = $errorValues;
916 $fd = fopen($fileName, 'w');
918 foreach ($header as $key => $value) {
919 $header[$key] = "\"$value\"";
921 $config = CRM_Core_Config
::singleton();
922 $output[] = implode($config->fieldSeparator
, $header);
924 foreach ($data as $datum) {
925 foreach ($datum as $key => $value) {
926 $datum[$key] = "\"$value\"";
928 $output[] = implode($config->fieldSeparator
, $datum);
930 fwrite($fd, implode("\n", $output));
935 * Update the record with PK $id in the import database table
938 * @param array $params
943 public function updateImportRecord($id, &$params) {
944 $statusFieldName = $this->_statusFieldName
;
945 $primaryKeyName = $this->_primaryKeyName
;
947 if ($statusFieldName && $primaryKeyName) {
948 $dao = new CRM_Core_DAO();
949 $db = $dao->getDatabaseConnection();
951 $query = "UPDATE $this->_tableName
952 SET $statusFieldName = ?,
953 ${statusFieldName}Msg = ?
954 WHERE $primaryKeyName = ?";
956 $params[$statusFieldName],
957 CRM_Utils_Array
::value("${statusFieldName}Msg", $params),
961 //print "Running query: $query<br/>With arguments: ".$params[$statusFieldName].", ".$params["${statusFieldName}Msg"].", $id<br/>";
963 $db->query($query, $args);
967 function errorFileName($type) {
973 $config = CRM_Core_Config
::singleton();
974 $fileName = $config->uploadDir
. "sqlImport";
976 case CRM_Import_Parser
::ERROR
:
977 $fileName .= '.errors';
980 case CRM_Import_Parser
::CONFLICT
:
981 $fileName .= '.conflicts';
984 case CRM_Import_Parser
::DUPLICATE
:
985 $fileName .= '.duplicates';
988 case CRM_Import_Parser
::NO_MATCH
:
989 $fileName .= '.mismatch';
992 case CRM_Import_Parser
::UNPARSED_ADDRESS_WARNING
:
993 $fileName .= '.unparsedAddress';
1000 function saveFileName($type) {
1006 case CRM_Import_Parser
::ERROR
:
1007 $fileName = 'Import_Errors.csv';
1010 case CRM_Import_Parser
::CONFLICT
:
1011 $fileName = 'Import_Conflicts.csv';
1014 case CRM_Import_Parser
::DUPLICATE
:
1015 $fileName = 'Import_Duplicates.csv';
1018 case CRM_Import_Parser
::NO_MATCH
:
1019 $fileName = 'Import_Mismatch.csv';
1022 case CRM_Import_Parser
::UNPARSED_ADDRESS_WARNING
:
1023 $fileName = 'Import_Unparsed_Address.csv';