3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2017 |
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-2017
33 abstract class CRM_Import_Parser
{
37 const MAX_ERRORS
= 250, MAX_WARNINGS
= 25, DEFAULT_TIMEOUT
= 30;
42 const VALID
= 1, WARNING
= 2, ERROR
= 4, CONFLICT
= 8, STOP
= 16, DUPLICATE
= 32, MULTIPLE_DUPE
= 64, NO_MATCH
= 128, UNPARSED_ADDRESS_WARNING
= 256;
47 const MODE_MAPFIELD
= 1, MODE_PREVIEW
= 2, MODE_SUMMARY
= 4, MODE_IMPORT
= 8;
50 * Codes for duplicate record handling
52 const DUPLICATE_SKIP
= 1, DUPLICATE_REPLACE
= 2, DUPLICATE_UPDATE
= 4, DUPLICATE_FILL
= 8, DUPLICATE_NOCHECK
= 16;
57 const CONTACT_INDIVIDUAL
= 1, CONTACT_HOUSEHOLD
= 2, CONTACT_ORGANIZATION
= 4;
61 * Total number of non empty lines
63 protected $_totalCount;
66 * Running total number of valid lines
68 protected $_validCount;
71 * Running total number of invalid rows
73 protected $_invalidRowCount;
76 * Maximum number of non-empty/comment lines to process
80 protected $_maxLinesToProcess;
83 * Maximum number of invalid rows to store
85 protected $_maxErrorCount;
88 * Array of error lines, bounded by MAX_ERROR
93 * Total number of conflict lines
95 protected $_conflictCount;
98 * Array of conflict lines
100 protected $_conflicts;
103 * Total number of duplicate (from database) lines
105 protected $_duplicateCount;
108 * Array of duplicate lines
110 protected $_duplicates;
113 * Running total number of warnings
115 protected $_warningCount;
118 * Maximum number of warnings to store
120 protected $_maxWarningCount = self
::MAX_WARNINGS
;
123 * Array of warning lines, bounded by MAX_WARNING
125 protected $_warnings;
128 * Array of all the fields that could potentially be part
129 * of this import process
135 * Array of the fields that are actually part of the import process
136 * the position in the array also dictates their position in the import
140 protected $_activeFields;
143 * Cache the count of active fields
147 protected $_activeFieldCount;
150 * Cache of preview rows
157 * Filename of error data
161 protected $_errorFileName;
164 * Filename of conflict data
168 protected $_conflictFileName;
171 * Filename of duplicate data
175 protected $_duplicateFileName;
182 public $_contactType;
188 public $_contactSubType;
193 public function __construct() {
194 $this->_maxLinesToProcess
= 0;
195 $this->_maxErrorCount
= self
::MAX_ERRORS
;
199 * Abstract function definitions.
201 abstract protected function init();
206 abstract protected function fini();
211 * @param array $values
215 abstract protected function mapField(&$values);
220 * @param array $values
224 abstract protected function preview(&$values);
231 abstract protected function summary(&$values);
234 * @param $onDuplicate
239 abstract protected function import($onDuplicate, &$values);
242 * Set and validate field values.
244 * @param array $elements
246 * @param $erroneousField
251 public function setActiveFieldValues($elements, &$erroneousField) {
252 $maxCount = count($elements) < $this->_activeFieldCount ?
count($elements) : $this->_activeFieldCount
;
253 for ($i = 0; $i < $maxCount; $i++
) {
254 $this->_activeFields
[$i]->setValue($elements[$i]);
257 // reset all the values that we did not have an equivalent import element
258 for (; $i < $this->_activeFieldCount
; $i++
) {
259 $this->_activeFields
[$i]->resetValue();
262 // now validate the fields and return false if error
263 $valid = self
::VALID
;
264 for ($i = 0; $i < $this->_activeFieldCount
; $i++
) {
265 if (!$this->_activeFields
[$i]->validate()) {
266 // no need to do any more validation
267 $erroneousField = $i;
268 $valid = self
::ERROR
;
276 * Format the field values for input to the api.
279 * (reference) associative array of name/value pairs
281 public function &getActiveFieldParams() {
283 for ($i = 0; $i < $this->_activeFieldCount
; $i++
) {
284 if (isset($this->_activeFields
[$i]->_value
)
285 && !isset($params[$this->_activeFields
[$i]->_name
])
286 && !isset($this->_activeFields
[$i]->_related
)
289 $params[$this->_activeFields
[$i]->_name
] = $this->_activeFields
[$i]->_value
;
298 public function getSelectValues() {
300 foreach ($this->_fields
as $name => $field) {
301 $values[$name] = $field->_title
;
309 public function getSelectTypes() {
311 foreach ($this->_fields
as $name => $field) {
312 if (isset($field->_hasLocationType
)) {
313 $values[$name] = $field->_hasLocationType
;
322 public function getHeaderPatterns() {
324 foreach ($this->_fields
as $name => $field) {
325 if (isset($field->_headerPattern
)) {
326 $values[$name] = $field->_headerPattern
;
335 public function getDataPatterns() {
337 foreach ($this->_fields
as $name => $field) {
338 $values[$name] = $field->_dataPattern
;
344 * Remove single-quote enclosures from a value array (row).
346 * @param array $values
347 * @param string $enclosure
351 public static function encloseScrub(&$values, $enclosure = "'") {
352 if (empty($values)) {
356 foreach ($values as $k => $v) {
357 $values[$k] = preg_replace("/^$enclosure(.*)$enclosure$/", '$1', $v);
368 public function setMaxLinesToProcess($max) {
369 $this->_maxLinesToProcess
= $max;
373 * Determines the file extension based on error code.
375 * @var $type error code constant
378 public static function errorFileName($type) {
384 $config = CRM_Core_Config
::singleton();
385 $fileName = $config->uploadDir
. "sqlImport";
388 $fileName .= '.errors';
392 $fileName .= '.conflicts';
395 case self
::DUPLICATE
:
396 $fileName .= '.duplicates';
400 $fileName .= '.mismatch';
403 case self
::UNPARSED_ADDRESS_WARNING
:
404 $fileName .= '.unparsedAddress';
412 * Determines the file name based on error code.
414 * @var $type error code constant
417 public static function saveFileName($type) {
424 $fileName = 'Import_Errors.csv';
428 $fileName = 'Import_Conflicts.csv';
431 case self
::DUPLICATE
:
432 $fileName = 'Import_Duplicates.csv';
436 $fileName = 'Import_Mismatch.csv';
439 case self
::UNPARSED_ADDRESS_WARNING
:
440 $fileName = 'Import_Unparsed_Address.csv';