Merge remote-tracking branch 'upstream/4.3' into 4.3-master-2013-05-01-11-04-54
[civicrm-core.git] / CRM / Contribute / Import / Parser.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
38abstract class CRM_Contribute_Import_Parser {
39 CONST MAX_ERRORS = 250, MAX_WARNINGS = 25, VALID = 1, WARNING = 2, ERROR = 3, CONFLICT = 4, STOP = 5, DUPLICATE = 6, MULTIPLE_DUPE = 7, NO_MATCH = 8, SOFT_CREDIT = 9, SOFT_CREDIT_ERROR = 10, PLEDGE_PAYMENT = 11, PLEDGE_PAYMENT_ERROR = 12;
40
41 /**
42 * various parser modes
43 */
44 CONST MODE_MAPFIELD = 1, MODE_PREVIEW = 2, MODE_SUMMARY = 4, MODE_IMPORT = 8;
45
46 /**
47 * codes for duplicate record handling
48 */
49 CONST DUPLICATE_SKIP = 1, DUPLICATE_REPLACE = 2, DUPLICATE_UPDATE = 4, DUPLICATE_FILL = 8, DUPLICATE_NOCHECK = 16;
50
51 /**
52 * various Contact types
53 */
54 CONST CONTACT_INDIVIDUAL = 1, CONTACT_HOUSEHOLD = 2, CONTACT_ORGANIZATION = 4;
55
56 protected $_fileName;
57
58 /**#@+
59 * @access protected
60 * @var integer
61 */
62
63 /**
64 * imported file size
65 */
66 protected $_fileSize;
67
68 /**
69 * seperator being used
70 */
71 protected $_seperator;
72
73 /**
74 * total number of lines in file
75 */
76 protected $_lineCount;
77
78 /**
79 * total number of non empty lines
80 */
81 protected $_totalCount;
82
83 /**
84 * running total number of valid lines
85 */
86 protected $_validCount;
87
88 /**
89 * running total number of invalid rows
90 */
91 protected $_invalidRowCount;
92
93 /**
94 * running total number of valid soft credit rows
95 */
96 protected $_validSoftCreditRowCount;
97
98 /**
99 * running total number of invalid soft credit rows
100 */
101 protected $_invalidSoftCreditRowCount;
102
103 /**
104 * running total number of valid pledge payment rows
105 */
106 protected $_validPledgePaymentRowCount;
107
108 /**
109 * running total number of invalid pledge payment rows
110 */
111 protected $_invalidPledgePaymentRowCount;
112
113 /**
114 * maximum number of invalid rows to store
115 */
116 protected $_maxErrorCount;
117
118 /**
119 * array of error lines, bounded by MAX_ERROR
120 */
121 protected $_errors;
122
123 /**
124 * array of pledge payment error lines, bounded by MAX_ERROR
125 */
126 protected $_pledgePaymentErrors;
127
128 /**
129 * array of pledge payment error lines, bounded by MAX_ERROR
130 */
131 protected $_softCreditErrors;
132
133 /**
134 * total number of conflict lines
135 */
136 protected $_conflictCount;
137
138 /**
139 * array of conflict lines
140 */
141 protected $_conflicts;
142
143 /**
144 * total number of duplicate (from database) lines
145 */
146 protected $_duplicateCount;
147
148 /**
149 * array of duplicate lines
150 */
151 protected $_duplicates;
152
153 /**
154 * running total number of warnings
155 */
156 protected $_warningCount;
157
158 /**
159 * maximum number of warnings to store
160 */
161 protected $_maxWarningCount = self::MAX_WARNINGS;
162
163 /**
164 * array of warning lines, bounded by MAX_WARNING
165 */
166 protected $_warnings;
167
168 /**
169 * array of all the fields that could potentially be part
170 * of this import process
171 * @var array
172 */
173 protected $_fields;
174
175 /**
176 * array of the fields that are actually part of the import process
177 * the position in the array also dictates their position in the import
178 * file
179 * @var array
180 */
181 protected $_activeFields;
182
183 /**
184 * cache the count of active fields
185 *
186 * @var int
187 */
188 protected $_activeFieldCount;
189
190 /**
191 * maximum number of non-empty/comment lines to process
192 *
193 * @var int
194 */
195 protected $_maxLinesToProcess;
196
197 /**
198 * cache of preview rows
199 *
200 * @var array
201 */
202 protected $_rows;
203
204 /**
205 * filename of error data
206 *
207 * @var string
208 */
209 protected $_errorFileName;
210
211 /**
212 * filename of pledge payment error data
213 *
214 * @var string
215 */
216 protected $_pledgePaymentErrorsFileName;
217
218 /**
219 * filename of soft credit error data
220 *
221 * @var string
222 */
223 protected $_softCreditErrorsFileName;
224
225 /**
226 * filename of conflict data
227 *
228 * @var string
229 */
230 protected $_conflictFileName;
231
232 /**
233 * filename of duplicate data
234 *
235 * @var string
236 */
237 protected $_duplicateFileName;
238
239 /**
240 * whether the file has a column header or not
241 *
242 * @var boolean
243 */
244 protected $_haveColumnHeader;
245
246 /**
247 * contact type
248 *
249 * @var int
250 */
251
252 public $_contactType;
253
254 function __construct() {
255 $this->_maxLinesToProcess = 0;
256 $this->_maxErrorCount = self::MAX_ERRORS;
257 }
258
259 abstract function init();
260 function run($fileName,
261 $seperator = ',',
262 &$mapper,
263 $skipColumnHeader = FALSE,
264 $mode = self::MODE_PREVIEW,
265 $contactType = self::CONTACT_INDIVIDUAL,
266 $onDuplicate = self::DUPLICATE_SKIP
267 ) {
268 if (!is_array($fileName)) {
269 CRM_Core_Error::fatal();
270 }
271 $fileName = $fileName['name'];
272
273 switch ($contactType) {
274 case self::CONTACT_INDIVIDUAL:
275 $this->_contactType = 'Individual';
276 break;
277
278 case self::CONTACT_HOUSEHOLD:
279 $this->_contactType = 'Household';
280 break;
281
282 case self::CONTACT_ORGANIZATION:
283 $this->_contactType = 'Organization';
284 }
285
286 $this->init();
287
288 $this->_haveColumnHeader = $skipColumnHeader;
289
290 $this->_seperator = $seperator;
291
292 $fd = fopen($fileName, "r");
293 if (!$fd) {
294 return FALSE;
295 }
296
297 $this->_lineCount = $this->_warningCount = $this->_validSoftCreditRowCount = $this->_validPledgePaymentRowCount = 0;
298 $this->_invalidRowCount = $this->_validCount = $this->_invalidSoftCreditRowCount = $this->_invalidPledgePaymentRowCount = 0;
299 $this->_totalCount = $this->_conflictCount = 0;
300
301 $this->_errors = array();
302 $this->_warnings = array();
303 $this->_conflicts = array();
304 $this->_pledgePaymentErrors = array();
305 $this->_softCreditErrors = array();
306
307 $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2);
308
309 if ($mode == self::MODE_MAPFIELD) {
310 $this->_rows = array();
311 }
312 else {
313 $this->_activeFieldCount = count($this->_activeFields);
314 }
315
316 while (!feof($fd)) {
317 $this->_lineCount++;
318
319 $values = fgetcsv($fd, 8192, $seperator);
320 if (!$values) {
321 continue;
322 }
323
324 self::encloseScrub($values);
325
326 // skip column header if we're not in mapfield mode
327 if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) {
328 $skipColumnHeader = FALSE;
329 continue;
330 }
331
332 /* trim whitespace around the values */
333
334 $empty = TRUE;
335 foreach ($values as $k => $v) {
336 $values[$k] = trim($v, " \t\r\n");
337 }
338
339 if (CRM_Utils_System::isNull($values)) {
340 continue;
341 }
342
343 $this->_totalCount++;
344
345 if ($mode == self::MODE_MAPFIELD) {
346 $returnCode = $this->mapField($values);
347 }
348 elseif ($mode == self::MODE_PREVIEW) {
349 $returnCode = $this->preview($values);
350 }
351 elseif ($mode == self::MODE_SUMMARY) {
352 $returnCode = $this->summary($values);
353 }
354 elseif ($mode == self::MODE_IMPORT) {
355 $returnCode = $this->import($onDuplicate, $values);
356 }
357 else {
358 $returnCode = self::ERROR;
359 }
360
361 // note that a line could be valid but still produce a warning
362 if ($returnCode == self::VALID) {
363 $this->_validCount++;
364 if ($mode == self::MODE_MAPFIELD) {
365 $this->_rows[] = $values;
366 $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
367 }
368 }
369
370 if ($returnCode == self::SOFT_CREDIT) {
371 $this->_validSoftCreditRowCount++;
372 $this->_validCount++;
373 if ($mode == self::MODE_MAPFIELD) {
374 $this->_rows[] = $values;
375 $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
376 }
377 }
378
379 if ($returnCode == self::PLEDGE_PAYMENT) {
380 $this->_validPledgePaymentRowCount++;
381 $this->_validCount++;
382 if ($mode == self::MODE_MAPFIELD) {
383 $this->_rows[] = $values;
384 $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
385 }
386 }
387
388 if ($returnCode == self::WARNING) {
389 $this->_warningCount++;
390 if ($this->_warningCount < $this->_maxWarningCount) {
391 $this->_warningCount[] = $line;
392 }
393 }
394
395 if ($returnCode == self::ERROR) {
396 $this->_invalidRowCount++;
397 if ($this->_invalidRowCount < $this->_maxErrorCount) {
398 $recordNumber = $this->_lineCount;
399 if ($this->_haveColumnHeader) {
400 $recordNumber--;
401 }
402 array_unshift($values, $recordNumber);
403 $this->_errors[] = $values;
404 }
405 }
406
407 if ($returnCode == self::PLEDGE_PAYMENT_ERROR) {
408 $this->_invalidPledgePaymentRowCount++;
409 if ($this->_invalidPledgePaymentRowCount < $this->_maxErrorCount) {
410 $recordNumber = $this->_lineCount;
411 if ($this->_haveColumnHeader) {
412 $recordNumber--;
413 }
414 array_unshift($values, $recordNumber);
415 $this->_pledgePaymentErrors[] = $values;
416 }
417 }
418
419 if ($returnCode == self::SOFT_CREDIT_ERROR) {
420 $this->_invalidSoftCreditRowCount++;
421 if ($this->_invalidSoftCreditRowCount < $this->_maxErrorCount) {
422 $recordNumber = $this->_lineCount;
423 if ($this->_haveColumnHeader) {
424 $recordNumber--;
425 }
426 array_unshift($values, $recordNumber);
427 $this->_softCreditErrors[] = $values;
428 }
429 }
430
431 if ($returnCode == self::CONFLICT) {
432 $this->_conflictCount++;
433 $recordNumber = $this->_lineCount;
434 if ($this->_haveColumnHeader) {
435 $recordNumber--;
436 }
437 array_unshift($values, $recordNumber);
438 $this->_conflicts[] = $values;
439 }
440
441 if ($returnCode == self::DUPLICATE) {
442 if ($returnCode == self::MULTIPLE_DUPE) {
443 /* TODO: multi-dupes should be counted apart from singles
444 * on non-skip action */
445 }
446 $this->_duplicateCount++;
447 $recordNumber = $this->_lineCount;
448 if ($this->_haveColumnHeader) {
449 $recordNumber--;
450 }
451 array_unshift($values, $recordNumber);
452 $this->_duplicates[] = $values;
453 if ($onDuplicate != self::DUPLICATE_SKIP) {
454 $this->_validCount++;
455 }
456 }
457
458 // we give the derived class a way of aborting the process
459 // note that the return code could be multiple code or'ed together
460 if ($returnCode == self::STOP) {
461 break;
462 }
463
464 // if we are done processing the maxNumber of lines, break
465 if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
466 break;
467 }
468 }
469
470 fclose($fd);
471
472 if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
473 $customHeaders = $mapper;
474
475 $customfields = CRM_Core_BAO_CustomField::getFields('Contribution');
476 foreach ($customHeaders as $key => $value) {
477 if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
478 $customHeaders[$key] = $customfields[$id][0];
479 }
480 }
481 if ($this->_invalidRowCount) {
482 // removed view url for invlaid contacts
483 $headers = array_merge(array(ts('Line Number'),
484 ts('Reason'),
485 ),
486 $customHeaders
487 );
488 $this->_errorFileName = self::errorFileName(self::ERROR);
489 self::exportCSV($this->_errorFileName, $headers, $this->_errors);
490 }
491
492 if ($this->_invalidPledgePaymentRowCount) {
493 // removed view url for invlaid contacts
494 $headers = array_merge(array(ts('Line Number'),
495 ts('Reason'),
496 ),
497 $customHeaders
498 );
499 $this->_pledgePaymentErrorsFileName = self::errorFileName(self::PLEDGE_PAYMENT_ERROR);
500 self::exportCSV($this->_pledgePaymentErrorsFileName, $headers, $this->_pledgePaymentErrors);
501 }
502
503 if ($this->_invalidSoftCreditRowCount) {
504 // removed view url for invlaid contacts
505 $headers = array_merge(array(ts('Line Number'),
506 ts('Reason'),
507 ),
508 $customHeaders
509 );
510 $this->_softCreditErrorsFileName = self::errorFileName(self::SOFT_CREDIT_ERROR);
511 self::exportCSV($this->_softCreditErrorsFileName, $headers, $this->_softCreditErrors);
512 }
513
514 if ($this->_conflictCount) {
515 $headers = array_merge(array(ts('Line Number'),
516 ts('Reason'),
517 ),
518 $customHeaders
519 );
520 $this->_conflictFileName = self::errorFileName(self::CONFLICT);
521 self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
522 }
523 if ($this->_duplicateCount) {
524 $headers = array_merge(array(ts('Line Number'),
525 ts('View Contribution URL'),
526 ),
527 $customHeaders
528 );
529
530 $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
531 self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
532 }
533 }
534 //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
535 return $this->fini();
536 }
537
538 abstract function mapField(&$values);
539 abstract function preview(&$values);
540 abstract function summary(&$values);
541 abstract function import($onDuplicate, &$values);
542
543 abstract function fini();
544
545 /**
546 * Given a list of the importable field keys that the user has selected
547 * set the active fields array to this list
548 *
549 * @param array mapped array of values
550 *
551pppp * @return void
552 * @access public
553 */
554 function setActiveFields($fieldKeys) {
555 $this->_activeFieldCount = count($fieldKeys);
556 foreach ($fieldKeys as $key) {
557 if (empty($this->_fields[$key])) {
558 $this->_activeFields[] = new CRM_Contribute_Import_Field('', ts('- do not import -'));
559 }
560 else {
561 $this->_activeFields[] = clone($this->_fields[$key]);
562 }
563 }
564 }
565
566 function setActiveFieldSoftCredit($elements) {
567 for ($i = 0; $i < count($elements); $i++) {
568 $this->_activeFields[$i]->_softCreditField = $elements[$i];
569 }
570 }
571
572 function setActiveFieldValues($elements, &$erroneousField) {
573 $maxCount = count($elements) < $this->_activeFieldCount ? count($elements) : $this->_activeFieldCount;
574 for ($i = 0; $i < $maxCount; $i++) {
575 $this->_activeFields[$i]->setValue($elements[$i]);
576 }
577
578 // reset all the values that we did not have an equivalent import element
579 for (; $i < $this->_activeFieldCount; $i++) {
580 $this->_activeFields[$i]->resetValue();
581 }
582
583 // now validate the fields and return false if error
584 $valid = self::VALID;
585 for ($i = 0; $i < $this->_activeFieldCount; $i++) {
586 if (!$this->_activeFields[$i]->validate()) {
587 // no need to do any more validation
588 $erroneousField = $i;
589 $valid = self::ERROR;
590 break;
591 }
592 }
593 return $valid;
594 }
595
596 /**
597 * function to format the field values for input to the api
598 *
599 * @return array (reference ) associative array of name/value pairs
600 * @access public
601 */
602 function &getActiveFieldParams() {
603 $params = array();
604 for ($i = 0; $i < $this->_activeFieldCount; $i++) {
605 if (isset($this->_activeFields[$i]->_value)) {
606 if (isset($this->_activeFields[$i]->_softCreditField)) {
607 if (!isset($params[$this->_activeFields[$i]->_name])) {
608 $params[$this->_activeFields[$i]->_name] = array();
609 }
610 $params[$this->_activeFields[$i]->_name][$this->_activeFields[$i]->_softCreditField] = $this->_activeFields[$i]->_value;
611 }
612
613 if (!isset($params[$this->_activeFields[$i]->_name])) {
614 if (!isset($this->_activeFields[$i]->_softCreditField)) {
615 $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value;
616 }
617 }
618 }
619 }
620 return $params;
621 }
622
623 function getSelectValues() {
624 $values = array();
625 foreach ($this->_fields as $name => $field) {
626 $values[$name] = $field->_title;
627 }
628 return $values;
629 }
630
631 function getSelectTypes() {
632 $values = array();
633 foreach ($this->_fields as $name => $field) {
634 if (isset($field->_hasLocationType)) {
635 $values[$name] = $field->_hasLocationType;
636 }
637 }
638 return $values;
639 }
640
641 function getHeaderPatterns() {
642 $values = array();
643 foreach ($this->_fields as $name => $field) {
644 if (isset($field->_headerPattern)) {
645 $values[$name] = $field->_headerPattern;
646 }
647 }
648 return $values;
649 }
650
651 function getDataPatterns() {
652 $values = array();
653 foreach ($this->_fields as $name => $field) {
654 $values[$name] = $field->_dataPattern;
655 }
656 return $values;
657 }
658
659 function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') {
660 if (empty($name)) {
661 $this->_fields['doNotImport'] = new CRM_Contribute_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
662 }
663 else {
664 $tempField = CRM_Contact_BAO_Contact::importableFields('All', NULL);
665 if (!array_key_exists($name, $tempField)) {
666 $this->_fields[$name] = new CRM_Contribute_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
667 }
668 else {
669 $this->_fields[$name] = new CRM_Import_Field($name, $title, $type, $headerPattern, $dataPattern,
670 CRM_Utils_Array::value('hasLocationType', $tempField[$name])
671 );
672 }
673 }
674 }
675
676 /**
677 * setter function
678 *
679 * @param int $max
680 *
681 * @return void
682 * @access public
683 */
684 function setMaxLinesToProcess($max) {
685 $this->_maxLinesToProcess = $max;
686 }
687
688 /**
689 * Store parser values
690 *
691 * @param CRM_Core_Session $store
692 *
693 * @return void
694 * @access public
695 */
696 function set($store, $mode = self::MODE_SUMMARY) {
697 $store->set('fileSize', $this->_fileSize);
698 $store->set('lineCount', $this->_lineCount);
699 $store->set('seperator', $this->_seperator);
700 $store->set('fields', $this->getSelectValues());
701 $store->set('fieldTypes', $this->getSelectTypes());
702
703 $store->set('headerPatterns', $this->getHeaderPatterns());
704 $store->set('dataPatterns', $this->getDataPatterns());
705 $store->set('columnCount', $this->_activeFieldCount);
706
707 $store->set('totalRowCount', $this->_totalCount);
708 $store->set('validRowCount', $this->_validCount);
709 $store->set('invalidRowCount', $this->_invalidRowCount);
710 $store->set('invalidSoftCreditRowCount', $this->_invalidSoftCreditRowCount);
711 $store->set('validSoftCreditRowCount', $this->_validSoftCreditRowCount);
712 $store->set('invalidPledgePaymentRowCount', $this->_invalidPledgePaymentRowCount);
713 $store->set('validPledgePaymentRowCount', $this->_validPledgePaymentRowCount);
714 $store->set('conflictRowCount', $this->_conflictCount);
715
716 switch ($this->_contactType) {
717 case 'Individual':
718 $store->set('contactType', CRM_Contribute_Import_Parser::CONTACT_INDIVIDUAL);
719 break;
720
721 case 'Household':
722 $store->set('contactType', CRM_Contribute_Import_Parser::CONTACT_HOUSEHOLD);
723 break;
724
725 case 'Organization':
726 $store->set('contactType', CRM_Contribute_Import_Parser::CONTACT_ORGANIZATION);
727 }
728
729 if ($this->_invalidRowCount) {
730 $store->set('errorsFileName', $this->_errorFileName);
731 }
732 if ($this->_conflictCount) {
733 $store->set('conflictsFileName', $this->_conflictFileName);
734 }
735 if (isset($this->_rows) && !empty($this->_rows)) {
736 $store->set('dataValues', $this->_rows);
737 }
738
739 if ($this->_invalidPledgePaymentRowCount) {
740 $store->set('pledgePaymentErrorsFileName', $this->_pledgePaymentErrorsFileName);
741 }
742
743 if ($this->_invalidSoftCreditRowCount) {
744 $store->set('softCreditErrorsFileName', $this->_softCreditErrorsFileName);
745 }
746
747 if ($mode == self::MODE_IMPORT) {
748 $store->set('duplicateRowCount', $this->_duplicateCount);
749 if ($this->_duplicateCount) {
750 $store->set('duplicatesFileName', $this->_duplicateFileName);
751 }
752 }
753 //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
754 }
755
756 /**
757 * Export data to a CSV file
758 *
759 * @param string $filename
760 * @param array $header
761 * @param data $data
762 *
763 * @return void
764 * @access public
765 */
766 static function exportCSV($fileName, $header, $data) {
767 $output = array();
768 $fd = fopen($fileName, 'w');
769
770 foreach ($header as $key => $value) {
771 $header[$key] = "\"$value\"";
772 }
773 $config = CRM_Core_Config::singleton();
774 $output[] = implode($config->fieldSeparator, $header);
775
776 foreach ($data as $datum) {
777 foreach ($datum as $key => $value) {
778 if (is_array($value[0])) {
779 foreach ($value[0] as $k1 => $v1) {
780 if ($k1 == 'location_type_id') {
781 continue;
782 }
783 $datum[$k1] = $v1;
784 }
785 }
786 else {
787 $datum[$key] = "\"$value\"";
788 }
789 }
790 $output[] = implode($config->fieldSeparator, $datum);
791 }
792 fwrite($fd, implode("\n", $output));
793 fclose($fd);
794 }
795
796 /**
797 * Remove single-quote enclosures from a value array (row)
798 *
799 * @param array $values
800 * @param string $enclosure
801 *
802 * @return void
803 * @static
804 * @access public
805 */
806 static function encloseScrub(&$values, $enclosure = "'") {
807 if (empty($values)) {
808 return;
809 }
810
811 foreach ($values as $k => $v) {
812 $values[$k] = preg_replace("/^$enclosure(.*) $enclosure$/", '$1', $v);
813 }
814 }
815
816 function errorFileName($type) {
817 $fileName = NULL;
818 if (empty($type)) {
819 return $fileName;
820 }
821
822 $config = CRM_Core_Config::singleton();
823 $fileName = $config->uploadDir . "sqlImport";
824
825 switch ($type) {
826 case CRM_Contribute_Import_Parser::ERROR:
827 case CRM_Contribute_Import_Parser::NO_MATCH:
828 case CRM_Contribute_Import_Parser::CONFLICT:
829 case CRM_Contribute_Import_Parser::DUPLICATE:
830 //here constants get collides.
831 if ($type == CRM_Contribute_Import_Parser::ERROR) {
832 $type = CRM_Import_Parser::ERROR;
833 }
834 elseif ($type == CRM_Contribute_Import_Parser::NO_MATCH) {
835 $type = CRM_Import_Parser::NO_MATCH;
836 }
837 elseif ($type == CRM_Contribute_Import_Parser::CONFLICT) {
838 $type = CRM_Import_Parser::CONFLICT;
839 }
840 else {
841 $type = CRM_Import_Parser::DUPLICATE;
842 }
843 $fileName = CRM_Import_Parser::errorFileName($type);
844 break;
845
846 case CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR:
847 $fileName .= '.softCreditErrors';
848 break;
849
850 case CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR:
851 $fileName .= '.pledgePaymentErrors';
852 break;
853 }
854
855 return $fileName;
856 }
857
858 function saveFileName($type) {
859 $fileName = NULL;
860 if (empty($type)) {
861 return $fileName;
862 }
863
864 switch ($type) {
865 case CRM_Contribute_Import_Parser::ERROR:
866 case CRM_Contribute_Import_Parser::NO_MATCH:
867 case CRM_Contribute_Import_Parser::CONFLICT:
868 case CRM_Contribute_Import_Parser::DUPLICATE:
869 //here constants get collides.
870 if ($type == CRM_Contribute_Import_Parser::ERROR) {
871 $type = CRM_Import_Parser::ERROR;
872 }
873 elseif ($type == CRM_Contribute_Import_Parser::NO_MATCH) {
874 $type = CRM_Import_Parser::NO_MATCH;
875 }
876 elseif ($type == CRM_Contribute_Import_Parser::CONFLICT) {
877 $type = CRM_Import_Parser::CONFLICT;
878 }
879 else {
880 $type = CRM_Import_Parser::DUPLICATE;
881 }
882 $fileName = CRM_Import_Parser::saveFileName($type);
883 break;
884
885 case CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR:
886 $fileName = 'Import_Soft_Credit_Errors.csv';
887 break;
888
889 case CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR:
890 $fileName = 'Import_Pledge_Payment_Errors.csv';
891 break;
892 }
893
894 return $fileName;
895 }
896}
897