"CRM_Contact_BAO_Relationship::relatedMemberships()": "toxicAlert",
"CRM_Contact_Form_Contact::postProcess()": "toxicAlert",
"CRM_Contact_Import_Form_MapField::buildQuickForm()": "toxicAlert",
- "CRM_Contact_Import_Parser::formatCommonData()": "toxicAlert",
- "CRM_Contact_Import_Parser::formatContactParameters()": "toxicAlert",
- "CRM_Contact_Import_Parser::run()": "toxicAlert",
+ "CRM_Contact_Import_Parser_Contact::formatCommonData()": "toxicAlert",
+ "CRM_Contact_Import_Parser_Contact::formatContactParameters()": "toxicAlert",
+ "CRM_Contact_Import_Parser_Contact::run()": "toxicAlert",
"CRM_Contact_Import_Parser_Contact::import()": "toxicAlert",
"CRM_Contribute_BAO_Contribution::recordFinancialAccounts()": "toxicAlert",
"CRM_Contribute_BAO_Contribution::transitionComponents()": "toxicAlert",
"api_v3_JobTest::getMergeLocations()": "toxicAlert",
"api_v3_JobTest::getMergeSets()": "toxicAlert"
}
-}
\ No newline at end of file
+}
$this->assign('savedMappingName', $mappingId ? $mapDAO->name : NULL);
if ($invalidRowCount) {
- $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
if ($conflictRowCount) {
- $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
if ($mismatchCount) {
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
fclose($fd);
$this->set('errorFile', $errorFile);
- $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
- $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
}
$onDuplicate = $this->get('onDuplicate');
$mismatchCount = $this->get('unMatchCount');
if ($duplicateRowCount > 0) {
- $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadDuplicateRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
elseif ($mismatchCount) {
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser_Activity';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
else {
+++ /dev/null
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved. |
- | |
- | This work is published under the GNU AGPLv3 license with some |
- | permitted exceptions and without any warranty. For full license |
- | and copyright information, see https://civicrm.org/licensing |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- */
-abstract class CRM_Activity_Import_Parser extends CRM_Import_Parser {
-
- protected $_fileName;
-
- /**
- * Imported file size.
- * @var int
- */
- protected $_fileSize;
-
- /**
- * Separator being used.
- * @var string
- */
- protected $_separator;
-
- /**
- * Total number of lines in file.
- * @var int
- */
- protected $_lineCount;
-
- /**
- * Whether the file has a column header or not.
- *
- * @var bool
- */
- protected $_haveColumnHeader;
-
- /**
- * @param array $fileName
- * @param string $separator
- * @param $mapper
- * @param bool $skipColumnHeader
- * @param int $mode
- * @param int $onDuplicate
- * @param int $statusID
- * @param int $totalRowCount
- *
- * @return mixed
- * @throws Exception
- */
- public function run(
- array $fileName,
- $separator,
- $mapper,
- $skipColumnHeader = FALSE,
- $mode = self::MODE_PREVIEW,
- $onDuplicate = self::DUPLICATE_SKIP,
- $statusID = NULL,
- $totalRowCount = NULL
- ) {
-
- $fileName = $fileName['name'];
-
- $this->init();
-
- $this->_haveColumnHeader = $skipColumnHeader;
-
- $this->_separator = $separator;
-
- $fd = fopen($fileName, "r");
- if (!$fd) {
- return FALSE;
- }
-
- $this->_lineCount = $this->_warningCount = 0;
- $this->_invalidRowCount = $this->_validCount = 0;
- $this->_totalCount = $this->_conflictCount = 0;
-
- $this->_errors = [];
- $this->_warnings = [];
- $this->_conflicts = [];
-
- $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2);
-
- if ($mode == self::MODE_MAPFIELD) {
- $this->_rows = [];
- }
- else {
- $this->_activeFieldCount = count($this->_activeFields);
- }
- if ($statusID) {
- $this->progressImport($statusID);
- $startTimestamp = $currTimestamp = $prevTimestamp = time();
- }
-
- while (!feof($fd)) {
- $this->_lineCount++;
-
- $values = fgetcsv($fd, 8192, $separator);
- if (!$values) {
- continue;
- }
-
- self::encloseScrub($values);
-
- // skip column header if we're not in mapfield mode
- if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) {
- $skipColumnHeader = FALSE;
- continue;
- }
-
- // Trim whitespace around the values.
-
- $empty = TRUE;
- foreach ($values as $k => $v) {
- $values[$k] = trim($v, " \t\r\n");
- }
-
- if (CRM_Utils_System::isNull($values)) {
- continue;
- }
-
- $this->_totalCount++;
-
- if ($mode == self::MODE_MAPFIELD) {
- $returnCode = $this->mapField($values);
- }
- elseif ($mode == self::MODE_PREVIEW) {
- $returnCode = $this->preview($values);
- }
- elseif ($mode == self::MODE_SUMMARY) {
- $returnCode = $this->summary($values);
- }
- elseif ($mode == self::MODE_IMPORT) {
- $returnCode = $this->import($onDuplicate, $values);
- if ($statusID && (($this->_lineCount % 50) == 0)) {
- $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
- }
- }
- else {
- $returnCode = self::ERROR;
- }
-
- // note that a line could be valid but still produce a warning
- if ($returnCode & self::VALID) {
- $this->_validCount++;
- if ($mode == self::MODE_MAPFIELD) {
- $this->_rows[] = $values;
- $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
- }
- }
-
- if ($returnCode & self::WARNING) {
- $this->_warningCount++;
- if ($this->_warningCount < $this->_maxWarningCount) {
- $this->_warningCount[] = $line;
- }
- }
-
- if ($returnCode & self::ERROR) {
- $this->_invalidRowCount++;
- $recordNumber = $this->_lineCount;
- if ($this->_haveColumnHeader) {
- $recordNumber--;
- }
- array_unshift($values, $recordNumber);
- $this->_errors[] = $values;
- }
-
- if ($returnCode & self::CONFLICT) {
- $this->_conflictCount++;
- $recordNumber = $this->_lineCount;
- if ($this->_haveColumnHeader) {
- $recordNumber--;
- }
- array_unshift($values, $recordNumber);
- $this->_conflicts[] = $values;
- }
-
- if ($returnCode & self::DUPLICATE) {
- $this->_duplicateCount++;
- $recordNumber = $this->_lineCount;
- if ($this->_haveColumnHeader) {
- $recordNumber--;
- }
- array_unshift($values, $recordNumber);
- $this->_duplicates[] = $values;
- if ($onDuplicate != self::DUPLICATE_SKIP) {
- $this->_validCount++;
- }
- }
-
- // we give the derived class a way of aborting the process
- // note that the return code could be multiple code or'ed together
- if ($returnCode & self::STOP) {
- break;
- }
-
- // if we are done processing the maxNumber of lines, break
- if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
- break;
- }
- }
-
- fclose($fd);
-
- if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
- $customHeaders = $mapper;
-
- $customfields = CRM_Core_BAO_CustomField::getFields('Activity');
- foreach ($customHeaders as $key => $value) {
- if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
- $customHeaders[$key] = $customfields[$id][0];
- }
- }
- if ($this->_invalidRowCount) {
- // removed view url for invlaid contacts
- $headers = array_merge(
- [ts('Line Number'), ts('Reason')],
- $customHeaders
- );
- $this->_errorFileName = self::errorFileName(self::ERROR);
- self::exportCSV($this->_errorFileName, $headers, $this->_errors);
- }
- if ($this->_conflictCount) {
- $headers = array_merge(
- [ts('Line Number'), ts('Reason')],
- $customHeaders
- );
- $this->_conflictFileName = self::errorFileName(self::CONFLICT);
- self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
- }
- if ($this->_duplicateCount) {
- $headers = array_merge(
- [ts('Line Number'), ts('View Activity History URL')],
- $customHeaders
- );
-
- $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
- self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
- }
- }
- return $this->fini();
- }
-
- /**
- * Given a list of the importable field keys that the user has selected set the active fields array to this list.
- *
- * @param array $fieldKeys
- */
- public function setActiveFields($fieldKeys) {
- $this->_activeFieldCount = count($fieldKeys);
- foreach ($fieldKeys as $key) {
- if (empty($this->_fields[$key])) {
- $this->_activeFields[] = new CRM_Activity_Import_Field('', ts('- do not import -'));
- }
- else {
- $this->_activeFields[] = clone($this->_fields[$key]);
- }
- }
- }
-
- /**
- * @param string $name
- * @param $title
- * @param int $type
- * @param string $headerPattern
- * @param string $dataPattern
- */
- public function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') {
- if (empty($name)) {
- $this->_fields['doNotImport'] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
- }
- else {
-
- $tempField = CRM_Contact_BAO_Contact::importableFields('Individual', NULL);
- if (!array_key_exists($name, $tempField)) {
- $this->_fields[$name] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
- }
- else {
- $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, CRM_Utils_Array::value('hasLocationType', $tempField[$name]));
- }
- }
- }
-
- /**
- * Store parser values.
- *
- * @param CRM_Core_Session $store
- *
- * @param int $mode
- */
- public function set($store, $mode = self::MODE_SUMMARY) {
- $store->set('fileSize', $this->_fileSize);
- $store->set('lineCount', $this->_lineCount);
- $store->set('separator', $this->_separator);
- $store->set('fields', $this->getSelectValues());
-
- $store->set('headerPatterns', $this->getHeaderPatterns());
- $store->set('dataPatterns', $this->getDataPatterns());
- $store->set('columnCount', $this->_activeFieldCount);
-
- $store->set('totalRowCount', $this->_totalCount);
- $store->set('validRowCount', $this->_validCount);
- $store->set('invalidRowCount', $this->_invalidRowCount);
- $store->set('conflictRowCount', $this->_conflictCount);
-
- if ($this->_invalidRowCount) {
- $store->set('errorsFileName', $this->_errorFileName);
- }
- if ($this->_conflictCount) {
- $store->set('conflictsFileName', $this->_conflictFileName);
- }
- if (isset($this->_rows) && !empty($this->_rows)) {
- $store->set('dataValues', $this->_rows);
- }
-
- if ($mode == self::MODE_IMPORT) {
- $store->set('duplicateRowCount', $this->_duplicateCount);
- if ($this->_duplicateCount) {
- $store->set('duplicatesFileName', $this->_duplicateFileName);
- }
- }
- }
-
- /**
- * Export data to a CSV file.
- *
- * @param string $fileName
- * @param array $header
- * @param array $data
- */
- public static function exportCSV($fileName, $header, $data) {
- $output = [];
- $fd = fopen($fileName, 'w');
-
- foreach ($header as $key => $value) {
- $header[$key] = "\"$value\"";
- }
- $config = CRM_Core_Config::singleton();
- $output[] = implode($config->fieldSeparator, $header);
-
- foreach ($data as $datum) {
- foreach ($datum as $key => $value) {
- $datum[$key] = "\"$value\"";
- }
- $output[] = implode($config->fieldSeparator, $datum);
- }
- fwrite($fd, implode("\n", $output));
- fclose($fd);
- }
-
-}
/**
* Class to parse activity csv files.
*/
-class CRM_Activity_Import_Parser_Activity extends CRM_Activity_Import_Parser {
+class CRM_Activity_Import_Parser_Activity extends CRM_Import_Parser {
protected $_mapperKeys;
*/
protected $_newActivity;
+ protected $_fileName;
+
+ /**
+ * Imported file size.
+ * @var int
+ */
+ protected $_fileSize;
+
+ /**
+ * Separator being used.
+ * @var string
+ */
+ protected $_separator;
+
+ /**
+ * Total number of lines in file.
+ * @var int
+ */
+ protected $_lineCount;
+
+ /**
+ * Whether the file has a column header or not.
+ *
+ * @var bool
+ */
+ protected $_haveColumnHeader;
+
/**
* Class constructor.
*
return $params;
}
+ /**
+ * @param array $fileName
+ * @param string $separator
+ * @param $mapper
+ * @param bool $skipColumnHeader
+ * @param int $mode
+ * @param int $onDuplicate
+ * @param int $statusID
+ * @param int $totalRowCount
+ *
+ * @return mixed
+ * @throws Exception
+ */
+ public function run(
+ array $fileName,
+ $separator,
+ $mapper,
+ $skipColumnHeader = FALSE,
+ $mode = self::MODE_PREVIEW,
+ $onDuplicate = self::DUPLICATE_SKIP,
+ $statusID = NULL,
+ $totalRowCount = NULL
+ ) {
+
+ $fileName = $fileName['name'];
+
+ $this->init();
+
+ $this->_haveColumnHeader = $skipColumnHeader;
+
+ $this->_separator = $separator;
+
+ $fd = fopen($fileName, "r");
+ if (!$fd) {
+ return FALSE;
+ }
+
+ $this->_lineCount = $this->_warningCount = 0;
+ $this->_invalidRowCount = $this->_validCount = 0;
+ $this->_totalCount = $this->_conflictCount = 0;
+
+ $this->_errors = [];
+ $this->_warnings = [];
+ $this->_conflicts = [];
+
+ $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2);
+
+ if ($mode == self::MODE_MAPFIELD) {
+ $this->_rows = [];
+ }
+ else {
+ $this->_activeFieldCount = count($this->_activeFields);
+ }
+ if ($statusID) {
+ $this->progressImport($statusID);
+ $startTimestamp = $currTimestamp = $prevTimestamp = time();
+ }
+
+ while (!feof($fd)) {
+ $this->_lineCount++;
+
+ $values = fgetcsv($fd, 8192, $separator);
+ if (!$values) {
+ continue;
+ }
+
+ self::encloseScrub($values);
+
+ // skip column header if we're not in mapfield mode
+ if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) {
+ $skipColumnHeader = FALSE;
+ continue;
+ }
+
+ // Trim whitespace around the values.
+
+ $empty = TRUE;
+ foreach ($values as $k => $v) {
+ $values[$k] = trim($v, " \t\r\n");
+ }
+
+ if (CRM_Utils_System::isNull($values)) {
+ continue;
+ }
+
+ $this->_totalCount++;
+
+ if ($mode == self::MODE_MAPFIELD) {
+ $returnCode = $this->mapField($values);
+ }
+ elseif ($mode == self::MODE_PREVIEW) {
+ $returnCode = $this->preview($values);
+ }
+ elseif ($mode == self::MODE_SUMMARY) {
+ $returnCode = $this->summary($values);
+ }
+ elseif ($mode == self::MODE_IMPORT) {
+ $returnCode = $this->import($onDuplicate, $values);
+ if ($statusID && (($this->_lineCount % 50) == 0)) {
+ $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
+ }
+ }
+ else {
+ $returnCode = self::ERROR;
+ }
+
+ // note that a line could be valid but still produce a warning
+ if ($returnCode & self::VALID) {
+ $this->_validCount++;
+ if ($mode == self::MODE_MAPFIELD) {
+ $this->_rows[] = $values;
+ $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
+ }
+ }
+
+ if ($returnCode & self::WARNING) {
+ $this->_warningCount++;
+ if ($this->_warningCount < $this->_maxWarningCount) {
+ $this->_warningCount[] = $line;
+ }
+ }
+
+ if ($returnCode & self::ERROR) {
+ $this->_invalidRowCount++;
+ $recordNumber = $this->_lineCount;
+ if ($this->_haveColumnHeader) {
+ $recordNumber--;
+ }
+ array_unshift($values, $recordNumber);
+ $this->_errors[] = $values;
+ }
+
+ if ($returnCode & self::CONFLICT) {
+ $this->_conflictCount++;
+ $recordNumber = $this->_lineCount;
+ if ($this->_haveColumnHeader) {
+ $recordNumber--;
+ }
+ array_unshift($values, $recordNumber);
+ $this->_conflicts[] = $values;
+ }
+
+ if ($returnCode & self::DUPLICATE) {
+ $this->_duplicateCount++;
+ $recordNumber = $this->_lineCount;
+ if ($this->_haveColumnHeader) {
+ $recordNumber--;
+ }
+ array_unshift($values, $recordNumber);
+ $this->_duplicates[] = $values;
+ if ($onDuplicate != self::DUPLICATE_SKIP) {
+ $this->_validCount++;
+ }
+ }
+
+ // we give the derived class a way of aborting the process
+ // note that the return code could be multiple code or'ed together
+ if ($returnCode & self::STOP) {
+ break;
+ }
+
+ // if we are done processing the maxNumber of lines, break
+ if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
+ break;
+ }
+ }
+
+ fclose($fd);
+
+ if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
+ $customHeaders = $mapper;
+
+ $customfields = CRM_Core_BAO_CustomField::getFields('Activity');
+ foreach ($customHeaders as $key => $value) {
+ if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
+ $customHeaders[$key] = $customfields[$id][0];
+ }
+ }
+ if ($this->_invalidRowCount) {
+ // removed view url for invlaid contacts
+ $headers = array_merge(
+ [ts('Line Number'), ts('Reason')],
+ $customHeaders
+ );
+ $this->_errorFileName = self::errorFileName(self::ERROR);
+ self::exportCSV($this->_errorFileName, $headers, $this->_errors);
+ }
+ if ($this->_conflictCount) {
+ $headers = array_merge(
+ [ts('Line Number'), ts('Reason')],
+ $customHeaders
+ );
+ $this->_conflictFileName = self::errorFileName(self::CONFLICT);
+ self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
+ }
+ if ($this->_duplicateCount) {
+ $headers = array_merge(
+ [ts('Line Number'), ts('View Activity History URL')],
+ $customHeaders
+ );
+
+ $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
+ self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
+ }
+ }
+ return $this->fini();
+ }
+
+ /**
+ * Given a list of the importable field keys that the user has selected set the active fields array to this list.
+ *
+ * @param array $fieldKeys
+ */
+ public function setActiveFields($fieldKeys) {
+ $this->_activeFieldCount = count($fieldKeys);
+ foreach ($fieldKeys as $key) {
+ if (empty($this->_fields[$key])) {
+ $this->_activeFields[] = new CRM_Activity_Import_Field('', ts('- do not import -'));
+ }
+ else {
+ $this->_activeFields[] = clone($this->_fields[$key]);
+ }
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param $title
+ * @param int $type
+ * @param string $headerPattern
+ * @param string $dataPattern
+ */
+ public function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') {
+ if (empty($name)) {
+ $this->_fields['doNotImport'] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
+ }
+ else {
+
+ $tempField = CRM_Contact_BAO_Contact::importableFields('Individual', NULL);
+ if (!array_key_exists($name, $tempField)) {
+ $this->_fields[$name] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
+ }
+ else {
+ $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, CRM_Utils_Array::value('hasLocationType', $tempField[$name]));
+ }
+ }
+ }
+
+ /**
+ * Store parser values.
+ *
+ * @param CRM_Core_Session $store
+ *
+ * @param int $mode
+ */
+ public function set($store, $mode = self::MODE_SUMMARY) {
+ $store->set('fileSize', $this->_fileSize);
+ $store->set('lineCount', $this->_lineCount);
+ $store->set('separator', $this->_separator);
+ $store->set('fields', $this->getSelectValues());
+
+ $store->set('headerPatterns', $this->getHeaderPatterns());
+ $store->set('dataPatterns', $this->getDataPatterns());
+ $store->set('columnCount', $this->_activeFieldCount);
+
+ $store->set('totalRowCount', $this->_totalCount);
+ $store->set('validRowCount', $this->_validCount);
+ $store->set('invalidRowCount', $this->_invalidRowCount);
+ $store->set('conflictRowCount', $this->_conflictCount);
+
+ if ($this->_invalidRowCount) {
+ $store->set('errorsFileName', $this->_errorFileName);
+ }
+ if ($this->_conflictCount) {
+ $store->set('conflictsFileName', $this->_conflictFileName);
+ }
+ if (isset($this->_rows) && !empty($this->_rows)) {
+ $store->set('dataValues', $this->_rows);
+ }
+
+ if ($mode == self::MODE_IMPORT) {
+ $store->set('duplicateRowCount', $this->_duplicateCount);
+ if ($this->_duplicateCount) {
+ $store->set('duplicatesFileName', $this->_duplicateFileName);
+ }
+ }
+ }
+
+ /**
+ * Export data to a CSV file.
+ *
+ * @param string $fileName
+ * @param array $header
+ * @param array $data
+ */
+ public static function exportCSV($fileName, $header, $data) {
+ $output = [];
+ $fd = fopen($fileName, 'w');
+
+ foreach ($header as $key => $value) {
+ $header[$key] = "\"$value\"";
+ }
+ $config = CRM_Core_Config::singleton();
+ $output[] = implode($config->fieldSeparator, $header);
+
+ foreach ($data as $datum) {
+ foreach ($datum as $key => $value) {
+ $datum[$key] = "\"$value\"";
+ }
+ $output[] = implode($config->fieldSeparator, $datum);
+ }
+ fwrite($fd, implode("\n", $output));
+ fclose($fd);
+ }
+
}
/**
* Get the id of the employee relationship, checking it is valid.
+ * We check that contact_type_a is Individual, but not contact_type_b because there's
+ * nowhere in the code that requires it to be Organization.
*
* @return int|string
*
$relationship = RelationshipType::get(FALSE)
->addWhere('name_a_b', '=', 'Employee of')
->addWhere('contact_type_a', '=', 'Individual')
- ->addWhere('contact_type_b', '=', 'Organization')
->addSelect('id')->execute()->first();
if (empty($relationship)) {
throw new API_Exception('no valid relationship');
$fieldNames['status'],
CRM_Import_Parser::DUPLICATE_SKIP,
NULL, NULL, FALSE,
- CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+ CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
$storeParams['contactSubType'],
$storeParams['dedupe']
);
$statusFieldName,
$this->_onDuplicate,
NULL, NULL, FALSE,
- CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+ CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
$this->get('contactSubType'),
$this->get('dedupe')
);
}
if ($invalidRowCount) {
- $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
if ($conflictRowCount) {
- $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
if ($mismatchCount) {
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
$this->set('errorFile', $errorFile);
- $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
- $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
$this->get('statusID'),
$this->get('totalRowCount'),
$doGeocodeAddress,
- CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+ CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
$this->get('contactSubType'),
$this->get('dedupe')
);
$this->set('errorFile', $errorFile);
- $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlparams));
- $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
}
$mismatchCount = $this->get('unMatchCount');
$unparsedAddressCount = $this->get('unparsedAddressCount');
if ($duplicateRowCount > 0) {
- $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadDuplicateRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
elseif ($mismatchCount) {
- $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
$this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
}
else {
$this->set('duplicateRowCount', $duplicateRowCount);
}
if ($unparsedAddressCount) {
- $urlParams = 'type=' . CRM_Import_Parser::UNPARSED_ADDRESS_WARNING . '&parser=CRM_Contact_Import_Parser';
+ $urlParams = 'type=' . CRM_Import_Parser::UNPARSED_ADDRESS_WARNING . '&parser=CRM_Contact_Import_Parser_Contact';
$this->assign('downloadAddressRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
$unparsedStreetAddressString = ts('Records imported successfully but unable to parse some of the street addresses');
$this->assign('unparsedStreetAddressString', $unparsedStreetAddressString);
$this->_statusID,
$this->_totalRowCount,
$this->_doGeocodeAddress,
- CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+ CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
$this->_contactSubType,
$this->_dedupe
);
+++ /dev/null
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved. |
- | |
- | This work is published under the GNU AGPLv3 license with some |
- | permitted exceptions and without any warranty. For full license |
- | and copyright information, see https://civicrm.org/licensing |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- */
-abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
-
- protected $_tableName;
-
- /**
- * Total number of lines in file
- *
- * @var int
- */
- protected $_rowCount;
-
- /**
- * Running total number of un-matched Contacts.
- *
- * @var int
- */
- protected $_unMatchCount;
-
- /**
- * Array of unmatched lines.
- *
- * @var array
- */
- protected $_unMatch;
-
- /**
- * Total number of contacts with unparsed addresses
- * @var int
- */
- protected $_unparsedAddressCount;
-
- /**
- * Filename of mismatch data
- *
- * @var string
- */
- protected $_misMatchFilemName;
-
- protected $_primaryKeyName;
- protected $_statusFieldName;
-
- protected $fieldMetadata = [];
- /**
- * On duplicate
- *
- * @var int
- */
- public $_onDuplicate;
-
- /**
- * Dedupe rule group id to use if set
- *
- * @var int
- */
- public $_dedupeRuleGroupID = NULL;
-
- /**
- * Run import.
- *
- * @param string $tableName
- * @param array $mapper
- * @param int $mode
- * @param int $contactType
- * @param string $primaryKeyName
- * @param string $statusFieldName
- * @param int $onDuplicate
- * @param int $statusID
- * @param int $totalRowCount
- * @param bool $doGeocodeAddress
- * @param int $timeout
- * @param string $contactSubType
- * @param int $dedupeRuleGroupID
- *
- * @return mixed
- */
- public function run(
- $tableName,
- $mapper = [],
- $mode = self::MODE_PREVIEW,
- $contactType = self::CONTACT_INDIVIDUAL,
- $primaryKeyName = '_id',
- $statusFieldName = '_status',
- $onDuplicate = self::DUPLICATE_SKIP,
- $statusID = NULL,
- $totalRowCount = NULL,
- $doGeocodeAddress = FALSE,
- $timeout = CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
- $contactSubType = NULL,
- $dedupeRuleGroupID = NULL
- ) {
-
- // TODO: Make the timeout actually work
- $this->_onDuplicate = $onDuplicate;
- $this->_dedupeRuleGroupID = $dedupeRuleGroupID;
-
- switch ($contactType) {
- case CRM_Import_Parser::CONTACT_INDIVIDUAL:
- $this->_contactType = 'Individual';
- break;
-
- case CRM_Import_Parser::CONTACT_HOUSEHOLD:
- $this->_contactType = 'Household';
- break;
-
- case CRM_Import_Parser::CONTACT_ORGANIZATION:
- $this->_contactType = 'Organization';
- }
-
- $this->_contactSubType = $contactSubType;
-
- $this->init();
-
- $this->_rowCount = $this->_warningCount = 0;
- $this->_invalidRowCount = $this->_validCount = 0;
- $this->_totalCount = $this->_conflictCount = 0;
-
- $this->_errors = [];
- $this->_warnings = [];
- $this->_conflicts = [];
- $this->_unparsedAddresses = [];
-
- $this->_tableName = $tableName;
- $this->_primaryKeyName = $primaryKeyName;
- $this->_statusFieldName = $statusFieldName;
-
- if ($mode == self::MODE_MAPFIELD) {
- $this->_rows = [];
- }
- else {
- $this->_activeFieldCount = count($this->_activeFields);
- }
-
- if ($mode == self::MODE_IMPORT) {
- //get the key of email field
- foreach ($mapper as $key => $value) {
- if (strtolower($value) == 'email') {
- $emailKey = $key;
- break;
- }
- }
- }
-
- if ($statusID) {
- $this->progressImport($statusID);
- $startTimestamp = $currTimestamp = $prevTimestamp = time();
- }
- // get the contents of the temp. import table
- $query = "SELECT * FROM $tableName";
- if ($mode == self::MODE_IMPORT) {
- $query .= " WHERE $statusFieldName = 'NEW'";
- }
-
- $result = CRM_Core_DAO::executeQuery($query);
-
- while ($result->fetch()) {
- $values = array_values($result->toArray());
- $this->_rowCount++;
-
- /* trim whitespace around the values */
- foreach ($values as $k => $v) {
- $values[$k] = trim($v, " \t\r\n");
- }
- if (CRM_Utils_System::isNull($values)) {
- continue;
- }
-
- $this->_totalCount++;
-
- if ($mode == self::MODE_MAPFIELD) {
- $returnCode = $this->mapField($values);
- }
- elseif ($mode == self::MODE_PREVIEW) {
- $returnCode = $this->preview($values);
- }
- elseif ($mode == self::MODE_SUMMARY) {
- $returnCode = $this->summary($values);
- }
- elseif ($mode == self::MODE_IMPORT) {
- //print "Running parser in import mode<br/>\n";
- $returnCode = $this->import($onDuplicate, $values, $doGeocodeAddress);
- if ($statusID && (($this->_rowCount % 50) == 0)) {
- $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
- }
- }
- else {
- $returnCode = self::ERROR;
- }
-
- // note that a line could be valid but still produce a warning
- if ($returnCode & self::VALID) {
- $this->_validCount++;
- if ($mode == self::MODE_MAPFIELD) {
- $this->_rows[] = $values;
- $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
- }
- }
-
- if ($returnCode & self::WARNING) {
- $this->_warningCount++;
- if ($this->_warningCount < $this->_maxWarningCount) {
- $this->_warningCount[] = $line;
- }
- }
-
- if ($returnCode & self::ERROR) {
- $this->_invalidRowCount++;
- array_unshift($values, $this->_rowCount);
- $this->_errors[] = $values;
- }
-
- if ($returnCode & self::CONFLICT) {
- $this->_conflictCount++;
- array_unshift($values, $this->_rowCount);
- $this->_conflicts[] = $values;
- }
-
- if ($returnCode & self::NO_MATCH) {
- $this->_unMatchCount++;
- array_unshift($values, $this->_rowCount);
- $this->_unMatch[] = $values;
- }
-
- if ($returnCode & self::DUPLICATE) {
- $this->_duplicateCount++;
- array_unshift($values, $this->_rowCount);
- $this->_duplicates[] = $values;
- if ($onDuplicate != self::DUPLICATE_SKIP) {
- $this->_validCount++;
- }
- }
-
- if ($returnCode & self::UNPARSED_ADDRESS_WARNING) {
- $this->_unparsedAddressCount++;
- array_unshift($values, $this->_rowCount);
- $this->_unparsedAddresses[] = $values;
- }
- // we give the derived class a way of aborting the process
- // note that the return code could be multiple code or'ed together
- if ($returnCode & self::STOP) {
- break;
- }
-
- // if we are done processing the maxNumber of lines, break
- if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
- break;
- }
-
- // see if we've hit our timeout yet
- /* if ( $the_thing_with_the_stuff ) {
- do_something( );
- } */
- }
-
- if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
- $customHeaders = $mapper;
-
- $customfields = CRM_Core_BAO_CustomField::getFields($this->_contactType);
- foreach ($customHeaders as $key => $value) {
- if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
- $customHeaders[$key] = $customfields[$id][0];
- }
- }
-
- if ($this->_invalidRowCount) {
- // removed view url for invlaid contacts
- $headers = array_merge([
- ts('Line Number'),
- ts('Reason'),
- ], $customHeaders);
- $this->_errorFileName = self::errorFileName(self::ERROR);
- self::exportCSV($this->_errorFileName, $headers, $this->_errors);
- }
- if ($this->_conflictCount) {
- $headers = array_merge([
- ts('Line Number'),
- ts('Reason'),
- ], $customHeaders);
- $this->_conflictFileName = self::errorFileName(self::CONFLICT);
- self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
- }
- if ($this->_duplicateCount) {
- $headers = array_merge([
- ts('Line Number'),
- ts('View Contact URL'),
- ], $customHeaders);
-
- $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
- self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
- }
- if ($this->_unMatchCount) {
- $headers = array_merge([
- ts('Line Number'),
- ts('Reason'),
- ], $customHeaders);
-
- $this->_misMatchFilemName = self::errorFileName(self::NO_MATCH);
- self::exportCSV($this->_misMatchFilemName, $headers, $this->_unMatch);
- }
- if ($this->_unparsedAddressCount) {
- $headers = array_merge([
- ts('Line Number'),
- ts('Contact Edit URL'),
- ], $customHeaders);
- $this->_errorFileName = self::errorFileName(self::UNPARSED_ADDRESS_WARNING);
- self::exportCSV($this->_errorFileName, $headers, $this->_unparsedAddresses);
- }
- }
- //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
- return $this->fini();
- }
-
- /**
- * Given a list of the importable field keys that the user has selected.
- * set the active fields array to this list
- *
- * @param array $fieldKeys
- * Mapped array of values.
- */
- public function setActiveFields($fieldKeys) {
- $this->_activeFieldCount = count($fieldKeys);
- foreach ($fieldKeys as $key) {
- if (empty($this->_fields[$key])) {
- $this->_activeFields[] = new CRM_Contact_Import_Field('', ts('- do not import -'));
- }
- else {
- $this->_activeFields[] = clone($this->_fields[$key]);
- }
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldLocationTypes($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_hasLocationType = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
-
- /**
- * @param $elements
- */
- public function setActiveFieldPhoneTypes($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_phoneType = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldWebsiteTypes($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_websiteType = $elements[$i];
- }
- }
-
- /**
- * Set IM Service Provider type fields.
- *
- * @param array $elements
- * IM service provider type ids.
- */
- public function setActiveFieldImProviders($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_imProvider = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldRelated($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_related = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldRelatedContactType($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_relatedContactType = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldRelatedContactDetails($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_relatedContactDetails = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldRelatedContactLocType($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_relatedContactLocType = $elements[$i];
- }
- }
-
- /**
- * Set active field for related contact's phone type.
- *
- * @param array $elements
- */
- public function setActiveFieldRelatedContactPhoneType($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_relatedContactPhoneType = $elements[$i];
- }
- }
-
- /**
- * @param $elements
- */
- public function setActiveFieldRelatedContactWebsiteType($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_relatedContactWebsiteType = $elements[$i];
- }
- }
-
- /**
- * Set IM Service Provider type fields for related contacts.
- *
- * @param array $elements
- * IM service provider type ids of related contact.
- */
- public function setActiveFieldRelatedContactImProvider($elements) {
- for ($i = 0; $i < count($elements); $i++) {
- $this->_activeFields[$i]->_relatedContactImProvider = $elements[$i];
- }
- }
-
- /**
- * Format the field values for input to the api.
- *
- * @return array
- * (reference ) associative array of name/value pairs
- */
- public function &getActiveFieldParams() {
- $params = [];
-
- for ($i = 0; $i < $this->_activeFieldCount; $i++) {
- if ($this->_activeFields[$i]->_name == 'do_not_import') {
- continue;
- }
-
- if (isset($this->_activeFields[$i]->_value)) {
- if (isset($this->_activeFields[$i]->_hasLocationType)) {
- if (!isset($params[$this->_activeFields[$i]->_name])) {
- $params[$this->_activeFields[$i]->_name] = [];
- }
-
- $value = [
- $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
- 'location_type_id' => $this->_activeFields[$i]->_hasLocationType,
- ];
-
- if (isset($this->_activeFields[$i]->_phoneType)) {
- $value['phone_type_id'] = $this->_activeFields[$i]->_phoneType;
- }
-
- // get IM service Provider type id
- if (isset($this->_activeFields[$i]->_imProvider)) {
- $value['provider_id'] = $this->_activeFields[$i]->_imProvider;
- }
-
- $params[$this->_activeFields[$i]->_name][] = $value;
- }
- elseif (isset($this->_activeFields[$i]->_websiteType)) {
- $value = [
- $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
- 'website_type_id' => $this->_activeFields[$i]->_websiteType,
- ];
-
- $params[$this->_activeFields[$i]->_name][] = $value;
- }
-
- if (!isset($params[$this->_activeFields[$i]->_name])) {
- if (!isset($this->_activeFields[$i]->_related)) {
- $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value;
- }
- }
-
- //minor fix for CRM-4062
- if (isset($this->_activeFields[$i]->_related)) {
- if (!isset($params[$this->_activeFields[$i]->_related])) {
- $params[$this->_activeFields[$i]->_related] = [];
- }
-
- if (!isset($params[$this->_activeFields[$i]->_related]['contact_type']) && !empty($this->_activeFields[$i]->_relatedContactType)) {
- $params[$this->_activeFields[$i]->_related]['contact_type'] = $this->_activeFields[$i]->_relatedContactType;
- }
-
- if (isset($this->_activeFields[$i]->_relatedContactLocType) && !empty($this->_activeFields[$i]->_value)) {
- if (!empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails]) &&
- !is_array($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])
- ) {
- $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
- }
- $value = [
- $this->_activeFields[$i]->_relatedContactDetails => $this->_activeFields[$i]->_value,
- 'location_type_id' => $this->_activeFields[$i]->_relatedContactLocType,
- ];
-
- if (isset($this->_activeFields[$i]->_relatedContactPhoneType)) {
- $value['phone_type_id'] = $this->_activeFields[$i]->_relatedContactPhoneType;
- }
-
- // get IM service Provider type id for related contact
- if (isset($this->_activeFields[$i]->_relatedContactImProvider)) {
- $value['provider_id'] = $this->_activeFields[$i]->_relatedContactImProvider;
- }
-
- $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = $value;
- }
- elseif (isset($this->_activeFields[$i]->_relatedContactWebsiteType)) {
- $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = [
- 'url' => $this->_activeFields[$i]->_value,
- 'website_type_id' => $this->_activeFields[$i]->_relatedContactWebsiteType,
- ];
- }
- elseif (empty($this->_activeFields[$i]->_value) && isset($this->_activeFields[$i]->_relatedContactLocType)) {
- if (empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])) {
- $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
- }
- }
- else {
- $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = $this->_activeFields[$i]->_value;
- }
- }
- }
- }
-
- return $params;
- }
-
- /**
- * @param string $name
- * @param $title
- * @param int $type
- * @param string $headerPattern
- * @param string $dataPattern
- * @param bool $hasLocationType
- */
- public function addField(
- $name, $title, $type = CRM_Utils_Type::T_INT,
- $headerPattern = '//', $dataPattern = '//',
- $hasLocationType = FALSE
- ) {
- $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
- if (empty($name)) {
- $this->_fields['doNotImport'] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
- }
- }
-
- /**
- * Store parser values.
- *
- * @param CRM_Core_Session $store
- *
- * @param int $mode
- */
- public function set($store, $mode = self::MODE_SUMMARY) {
- $store->set('rowCount', $this->_rowCount);
- $store->set('fields', $this->getSelectValues());
- $store->set('fieldTypes', $this->getSelectTypes());
-
- $store->set('columnCount', $this->_activeFieldCount);
-
- $store->set('totalRowCount', $this->_totalCount);
- $store->set('validRowCount', $this->_validCount);
- $store->set('invalidRowCount', $this->_invalidRowCount);
- $store->set('conflictRowCount', $this->_conflictCount);
- $store->set('unMatchCount', $this->_unMatchCount);
-
- switch ($this->_contactType) {
- case 'Individual':
- $store->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
- break;
-
- case 'Household':
- $store->set('contactType', CRM_Import_Parser::CONTACT_HOUSEHOLD);
- break;
-
- case 'Organization':
- $store->set('contactType', CRM_Import_Parser::CONTACT_ORGANIZATION);
- }
-
- if ($this->_invalidRowCount) {
- $store->set('errorsFileName', $this->_errorFileName);
- }
- if ($this->_conflictCount) {
- $store->set('conflictsFileName', $this->_conflictFileName);
- }
- if (isset($this->_rows) && !empty($this->_rows)) {
- $store->set('dataValues', $this->_rows);
- }
-
- if ($this->_unMatchCount) {
- $store->set('mismatchFileName', $this->_misMatchFilemName);
- }
-
- if ($mode == self::MODE_IMPORT) {
- $store->set('duplicateRowCount', $this->_duplicateCount);
- $store->set('unparsedAddressCount', $this->_unparsedAddressCount);
- if ($this->_duplicateCount) {
- $store->set('duplicatesFileName', $this->_duplicateFileName);
- }
- if ($this->_unparsedAddressCount) {
- $store->set('errorsFileName', $this->_errorFileName);
- }
- }
- //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
- }
-
- /**
- * Export data to a CSV file.
- *
- * @param string $fileName
- * @param array $header
- * @param array $data
- */
- public static function exportCSV($fileName, $header, $data) {
-
- if (file_exists($fileName) && !is_writable($fileName)) {
- CRM_Core_Error::movedSiteError($fileName);
- }
- //hack to remove '_status', '_statusMsg' and '_id' from error file
- $errorValues = [];
- $dbRecordStatus = ['IMPORTED', 'ERROR', 'DUPLICATE', 'INVALID', 'NEW'];
- foreach ($data as $rowCount => $rowValues) {
- $count = 0;
- foreach ($rowValues as $key => $val) {
- if (in_array($val, $dbRecordStatus) && $count == (count($rowValues) - 3)) {
- break;
- }
- $errorValues[$rowCount][$key] = $val;
- $count++;
- }
- }
- $data = $errorValues;
-
- $output = [];
- $fd = fopen($fileName, 'w');
-
- foreach ($header as $key => $value) {
- $header[$key] = "\"$value\"";
- }
- $config = CRM_Core_Config::singleton();
- $output[] = implode($config->fieldSeparator, $header);
-
- foreach ($data as $datum) {
- foreach ($datum as $key => $value) {
- $datum[$key] = "\"$value\"";
- }
- $output[] = implode($config->fieldSeparator, $datum);
- }
- fwrite($fd, implode("\n", $output));
- fclose($fd);
- }
-
- /**
- * Update the record with PK $id in the import database table.
- *
- * @deprecated - call setImportStatus directly as the parameters are simpler,
- *
- * @param int $id
- * @param array $params
- */
- public function updateImportRecord($id, $params): void {
- $this->setImportStatus((int) $id, $params[$this->_statusFieldName] ?? '', $params["{$this->_statusFieldName}Msg"] ?? '');
- }
-
- /**
- * Set the import status for the given record.
- *
- * If this is a sql import then the sql table will be used and the update
- * will not happen as the relevant fields don't exist in the table - hence
- * the checks that statusField & primary key are set.
- *
- * @param int $id
- * @param string $status
- * @param string $message
- */
- public function setImportStatus(int $id, string $status, string $message): void {
- if ($this->_statusFieldName && $this->_primaryKeyName) {
- CRM_Core_DAO::executeQuery("
- UPDATE $this->_tableName
- SET $this->_statusFieldName = %1,
- {$this->_statusFieldName}Msg = %2
- WHERE $this->_primaryKeyName = %3
- ", [
- 1 => [$status, 'String'],
- 2 => [$message, 'String'],
- 3 => [$id, 'Integer'],
- ]);
- }
- }
-
- /**
- * Format contact parameters.
- *
- * @todo this function needs re-writing & re-merging into the main function.
- *
- * Here be dragons.
- *
- * @param array $values
- * @param array $params
- *
- * @return bool
- */
- protected function formatContactParameters(&$values, &$params) {
- // Crawl through the possible classes:
- // Contact
- // Individual
- // Household
- // Organization
- // Location
- // Address
- // Email
- // Phone
- // IM
- // Note
- // Custom
-
- // first add core contact values since for other Civi modules they are not added
- $contactFields = CRM_Contact_DAO_Contact::fields();
- _civicrm_api3_store_values($contactFields, $values, $params);
-
- if (isset($values['contact_type'])) {
- // we're an individual/household/org property
-
- $fields[$values['contact_type']] = CRM_Contact_DAO_Contact::fields();
-
- _civicrm_api3_store_values($fields[$values['contact_type']], $values, $params);
- return TRUE;
- }
-
- // Cache the various object fields
- // @todo - remove this after confirming this is just a compilation of other-wise-cached fields.
- static $fields = [];
-
- if (isset($values['individual_prefix'])) {
- if (!empty($params['prefix_id'])) {
- $prefixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id');
- $params['prefix'] = $prefixes[$params['prefix_id']];
- }
- else {
- $params['prefix'] = $values['individual_prefix'];
- }
- return TRUE;
- }
-
- if (isset($values['individual_suffix'])) {
- if (!empty($params['suffix_id'])) {
- $suffixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id');
- $params['suffix'] = $suffixes[$params['suffix_id']];
- }
- else {
- $params['suffix'] = $values['individual_suffix'];
- }
- return TRUE;
- }
-
- // CRM-4575
- if (isset($values['email_greeting'])) {
- if (!empty($params['email_greeting_id'])) {
- $emailGreetingFilter = [
- 'contact_type' => $params['contact_type'] ?? NULL,
- 'greeting_type' => 'email_greeting',
- ];
- $emailGreetings = CRM_Core_PseudoConstant::greeting($emailGreetingFilter);
- $params['email_greeting'] = $emailGreetings[$params['email_greeting_id']];
- }
- else {
- $params['email_greeting'] = $values['email_greeting'];
- }
-
- return TRUE;
- }
-
- if (isset($values['postal_greeting'])) {
- if (!empty($params['postal_greeting_id'])) {
- $postalGreetingFilter = [
- 'contact_type' => $params['contact_type'] ?? NULL,
- 'greeting_type' => 'postal_greeting',
- ];
- $postalGreetings = CRM_Core_PseudoConstant::greeting($postalGreetingFilter);
- $params['postal_greeting'] = $postalGreetings[$params['postal_greeting_id']];
- }
- else {
- $params['postal_greeting'] = $values['postal_greeting'];
- }
- return TRUE;
- }
-
- if (isset($values['addressee'])) {
- $params['addressee'] = $values['addressee'];
- return TRUE;
- }
-
- if (isset($values['gender'])) {
- if (!empty($params['gender_id'])) {
- $genders = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id');
- $params['gender'] = $genders[$params['gender_id']];
- }
- else {
- $params['gender'] = $values['gender'];
- }
- return TRUE;
- }
-
- if (!empty($values['preferred_communication_method'])) {
- $comm = [];
- $pcm = array_change_key_case(array_flip(CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method')), CASE_LOWER);
-
- $preffComm = explode(',', $values['preferred_communication_method']);
- foreach ($preffComm as $v) {
- $v = strtolower(trim($v));
- if (array_key_exists($v, $pcm)) {
- $comm[$pcm[$v]] = 1;
- }
- }
-
- $params['preferred_communication_method'] = $comm;
- return TRUE;
- }
-
- // format the website params.
- if (!empty($values['url'])) {
- static $websiteFields;
- if (!is_array($websiteFields)) {
- $websiteFields = CRM_Core_DAO_Website::fields();
- }
- if (!array_key_exists('website', $params) ||
- !is_array($params['website'])
- ) {
- $params['website'] = [];
- }
-
- $websiteCount = count($params['website']);
- _civicrm_api3_store_values($websiteFields, $values,
- $params['website'][++$websiteCount]
- );
-
- return TRUE;
- }
-
- if (isset($values['note'])) {
- // add a note field
- if (!isset($params['note'])) {
- $params['note'] = [];
- }
- $noteBlock = count($params['note']) + 1;
-
- $params['note'][$noteBlock] = [];
- if (!isset($fields['Note'])) {
- $fields['Note'] = CRM_Core_DAO_Note::fields();
- }
-
- // get the current logged in civicrm user
- $session = CRM_Core_Session::singleton();
- $userID = $session->get('userID');
-
- if ($userID) {
- $values['contact_id'] = $userID;
- }
-
- _civicrm_api3_store_values($fields['Note'], $values, $params['note'][$noteBlock]);
-
- return TRUE;
- }
-
- // Check for custom field values
- $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $values),
- FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE
- );
-
- foreach ($values as $key => $value) {
- if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
- // check if it's a valid custom field id
-
- if (!array_key_exists($customFieldID, $customFields)) {
- return civicrm_api3_create_error('Invalid custom field ID');
- }
- else {
- $params[$key] = $value;
- }
- }
- }
- return TRUE;
- }
-
- /**
- * Format location block ready for importing.
- *
- * There is some test coverage for this in CRM_Contact_Import_Parser_ContactTest
- * e.g. testImportPrimaryAddress.
- *
- * @param array $values
- * @param array $params
- *
- * @return bool
- */
- protected function formatLocationBlock(&$values, &$params) {
- $blockTypes = [
- 'phone' => 'Phone',
- 'email' => 'Email',
- 'im' => 'IM',
- 'openid' => 'OpenID',
- 'phone_ext' => 'Phone',
- ];
- foreach ($blockTypes as $blockFieldName => $block) {
- if (!array_key_exists($blockFieldName, $values)) {
- continue;
- }
- $blockIndex = $values['location_type_id'] . (!empty($values['phone_type_id']) ? '_' . $values['phone_type_id'] : '');
-
- // block present in value array.
- if (!array_key_exists($blockFieldName, $params) || !is_array($params[$blockFieldName])) {
- $params[$blockFieldName] = [];
- }
-
- $fields[$block] = $this->getMetadataForEntity($block);
-
- // copy value to dao field name.
- if ($blockFieldName == 'im') {
- $values['name'] = $values[$blockFieldName];
- }
-
- _civicrm_api3_store_values($fields[$block], $values,
- $params[$blockFieldName][$blockIndex]
- );
-
- $this->fillPrimary($params[$blockFieldName][$blockIndex], $values, $block, CRM_Utils_Array::value('id', $params));
-
- if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
- $params[$blockFieldName][$blockIndex]['is_primary'] = TRUE;
- }
-
- // we only process single block at a time.
- return TRUE;
- }
-
- // handle address fields.
- if (!array_key_exists('address', $params) || !is_array($params['address'])) {
- $params['address'] = [];
- }
-
- // Note: we doing multiple value formatting here for address custom fields, plus putting into right format.
- // The actual formatting (like date, country ..etc) for address custom fields is taken care of while saving
- // the address in CRM_Core_BAO_Address::create method
- if (!empty($values['location_type_id'])) {
- static $customFields = [];
- if (empty($customFields)) {
- $customFields = CRM_Core_BAO_CustomField::getFields('Address');
- }
- // make a copy of values, as we going to make changes
- $newValues = $values;
- foreach ($values as $key => $val) {
- $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key);
- if ($customFieldID && array_key_exists($customFieldID, $customFields)) {
-
- $htmlType = $customFields[$customFieldID]['html_type'] ?? NULL;
- if (CRM_Core_BAO_CustomField::isSerialized($customFields[$customFieldID]) && $val) {
- $mulValues = explode(',', $val);
- $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE);
- $newValues[$key] = [];
- foreach ($mulValues as $v1) {
- foreach ($customOption as $v2) {
- if ((strtolower($v2['label']) == strtolower(trim($v1))) ||
- (strtolower($v2['value']) == strtolower(trim($v1)))
- ) {
- if ($htmlType == 'CheckBox') {
- $newValues[$key][$v2['value']] = 1;
- }
- else {
- $newValues[$key][] = $v2['value'];
- }
- }
- }
- }
- }
- }
- }
- // consider new values
- $values = $newValues;
- }
-
- $fields['Address'] = $this->getMetadataForEntity('Address');
- // @todo this is kinda replicated below....
- _civicrm_api3_store_values($fields['Address'], $values, $params['address'][$values['location_type_id']]);
-
- $addressFields = [
- 'county',
- 'country',
- 'state_province',
- 'supplemental_address_1',
- 'supplemental_address_2',
- 'supplemental_address_3',
- 'StateProvince.name',
- ];
- foreach (array_keys($customFields) as $customFieldID) {
- $addressFields[] = 'custom_' . $customFieldID;
- }
-
- foreach ($addressFields as $field) {
- if (array_key_exists($field, $values)) {
- if (!array_key_exists('address', $params)) {
- $params['address'] = [];
- }
- $params['address'][$values['location_type_id']][$field] = $values[$field];
- }
- }
-
- $this->fillPrimary($params['address'][$values['location_type_id']], $values, 'address', CRM_Utils_Array::value('id', $params));
- return TRUE;
- }
-
- /**
- * Get the field metadata for the relevant entity.
- *
- * @param string $entity
- *
- * @return array
- */
- protected function getMetadataForEntity($entity) {
- if (!isset($this->fieldMetadata[$entity])) {
- $className = "CRM_Core_DAO_$entity";
- $this->fieldMetadata[$entity] = $className::fields();
- }
- return $this->fieldMetadata[$entity];
- }
-
- /**
- * Fill in the primary location.
- *
- * If the contact has a primary address we update it. Otherwise
- * we add an address of the default location type.
- *
- * @param array $params
- * Address block parameters
- * @param array $values
- * Input values
- * @param string $entity
- * - address, email, phone
- * @param int|null $contactID
- *
- * @throws \CiviCRM_API3_Exception
- */
- protected function fillPrimary(&$params, $values, $entity, $contactID) {
- if ($values['location_type_id'] === 'Primary') {
- if ($contactID) {
- $primary = civicrm_api3($entity, 'get', [
- 'return' => 'location_type_id',
- 'contact_id' => $contactID,
- 'is_primary' => 1,
- 'sequential' => 1,
- ]);
- }
- $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
- $params['location_type_id'] = (int) (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
- $params['is_primary'] = 1;
- }
- }
-
-}
/**
* class to parse contact csv files
*/
-class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser {
+class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser {
use CRM_Contact_Import_MetadataTrait;
*/
protected $_unparsedStreetAddressContacts;
+ protected $_tableName;
+
+ /**
+ * Total number of lines in file
+ *
+ * @var int
+ */
+ protected $_rowCount;
+
+ /**
+ * Running total number of un-matched Contacts.
+ *
+ * @var int
+ */
+ protected $_unMatchCount;
+
+ /**
+ * Array of unmatched lines.
+ *
+ * @var array
+ */
+ protected $_unMatch;
+
+ /**
+ * Total number of contacts with unparsed addresses
+ * @var int
+ */
+ protected $_unparsedAddressCount;
+
+ /**
+ * Filename of mismatch data
+ *
+ * @var string
+ */
+ protected $_misMatchFilemName;
+
+ protected $_primaryKeyName;
+ protected $_statusFieldName;
+
+ protected $fieldMetadata = [];
+ /**
+ * On duplicate
+ *
+ * @var int
+ */
+ public $_onDuplicate;
+
+ /**
+ * Dedupe rule group id to use if set
+ *
+ * @var int
+ */
+ public $_dedupeRuleGroupID = NULL;
+
/**
* Class constructor.
*
}
}
+ /**
+ * Run import.
+ *
+ * @param string $tableName
+ * @param array $mapper
+ * @param int $mode
+ * @param int $contactType
+ * @param string $primaryKeyName
+ * @param string $statusFieldName
+ * @param int $onDuplicate
+ * @param int $statusID
+ * @param int $totalRowCount
+ * @param bool $doGeocodeAddress
+ * @param int $timeout
+ * @param string $contactSubType
+ * @param int $dedupeRuleGroupID
+ *
+ * @return mixed
+ */
+ public function run(
+ $tableName,
+ $mapper = [],
+ $mode = self::MODE_PREVIEW,
+ $contactType = self::CONTACT_INDIVIDUAL,
+ $primaryKeyName = '_id',
+ $statusFieldName = '_status',
+ $onDuplicate = self::DUPLICATE_SKIP,
+ $statusID = NULL,
+ $totalRowCount = NULL,
+ $doGeocodeAddress = FALSE,
+ $timeout = CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
+ $contactSubType = NULL,
+ $dedupeRuleGroupID = NULL
+ ) {
+
+ // TODO: Make the timeout actually work
+ $this->_onDuplicate = $onDuplicate;
+ $this->_dedupeRuleGroupID = $dedupeRuleGroupID;
+
+ switch ($contactType) {
+ case CRM_Import_Parser::CONTACT_INDIVIDUAL:
+ $this->_contactType = 'Individual';
+ break;
+
+ case CRM_Import_Parser::CONTACT_HOUSEHOLD:
+ $this->_contactType = 'Household';
+ break;
+
+ case CRM_Import_Parser::CONTACT_ORGANIZATION:
+ $this->_contactType = 'Organization';
+ }
+
+ $this->_contactSubType = $contactSubType;
+
+ $this->init();
+
+ $this->_rowCount = $this->_warningCount = 0;
+ $this->_invalidRowCount = $this->_validCount = 0;
+ $this->_totalCount = $this->_conflictCount = 0;
+
+ $this->_errors = [];
+ $this->_warnings = [];
+ $this->_conflicts = [];
+ $this->_unparsedAddresses = [];
+
+ $this->_tableName = $tableName;
+ $this->_primaryKeyName = $primaryKeyName;
+ $this->_statusFieldName = $statusFieldName;
+
+ if ($mode == self::MODE_MAPFIELD) {
+ $this->_rows = [];
+ }
+ else {
+ $this->_activeFieldCount = count($this->_activeFields);
+ }
+
+ if ($mode == self::MODE_IMPORT) {
+ //get the key of email field
+ foreach ($mapper as $key => $value) {
+ if (strtolower($value) == 'email') {
+ $emailKey = $key;
+ break;
+ }
+ }
+ }
+
+ if ($statusID) {
+ $this->progressImport($statusID);
+ $startTimestamp = $currTimestamp = $prevTimestamp = time();
+ }
+ // get the contents of the temp. import table
+ $query = "SELECT * FROM $tableName";
+ if ($mode == self::MODE_IMPORT) {
+ $query .= " WHERE $statusFieldName = 'NEW'";
+ }
+
+ $result = CRM_Core_DAO::executeQuery($query);
+
+ while ($result->fetch()) {
+ $values = array_values($result->toArray());
+ $this->_rowCount++;
+
+ /* trim whitespace around the values */
+ foreach ($values as $k => $v) {
+ $values[$k] = trim($v, " \t\r\n");
+ }
+ if (CRM_Utils_System::isNull($values)) {
+ continue;
+ }
+
+ $this->_totalCount++;
+
+ if ($mode == self::MODE_MAPFIELD) {
+ $returnCode = $this->mapField($values);
+ }
+ elseif ($mode == self::MODE_PREVIEW) {
+ $returnCode = $this->preview($values);
+ }
+ elseif ($mode == self::MODE_SUMMARY) {
+ $returnCode = $this->summary($values);
+ }
+ elseif ($mode == self::MODE_IMPORT) {
+ //print "Running parser in import mode<br/>\n";
+ $returnCode = $this->import($onDuplicate, $values, $doGeocodeAddress);
+ if ($statusID && (($this->_rowCount % 50) == 0)) {
+ $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
+ }
+ }
+ else {
+ $returnCode = self::ERROR;
+ }
+
+ // note that a line could be valid but still produce a warning
+ if ($returnCode & self::VALID) {
+ $this->_validCount++;
+ if ($mode == self::MODE_MAPFIELD) {
+ $this->_rows[] = $values;
+ $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
+ }
+ }
+
+ if ($returnCode & self::WARNING) {
+ $this->_warningCount++;
+ if ($this->_warningCount < $this->_maxWarningCount) {
+ $this->_warningCount[] = $line;
+ }
+ }
+
+ if ($returnCode & self::ERROR) {
+ $this->_invalidRowCount++;
+ array_unshift($values, $this->_rowCount);
+ $this->_errors[] = $values;
+ }
+
+ if ($returnCode & self::CONFLICT) {
+ $this->_conflictCount++;
+ array_unshift($values, $this->_rowCount);
+ $this->_conflicts[] = $values;
+ }
+
+ if ($returnCode & self::NO_MATCH) {
+ $this->_unMatchCount++;
+ array_unshift($values, $this->_rowCount);
+ $this->_unMatch[] = $values;
+ }
+
+ if ($returnCode & self::DUPLICATE) {
+ $this->_duplicateCount++;
+ array_unshift($values, $this->_rowCount);
+ $this->_duplicates[] = $values;
+ if ($onDuplicate != self::DUPLICATE_SKIP) {
+ $this->_validCount++;
+ }
+ }
+
+ if ($returnCode & self::UNPARSED_ADDRESS_WARNING) {
+ $this->_unparsedAddressCount++;
+ array_unshift($values, $this->_rowCount);
+ $this->_unparsedAddresses[] = $values;
+ }
+ // we give the derived class a way of aborting the process
+ // note that the return code could be multiple code or'ed together
+ if ($returnCode & self::STOP) {
+ break;
+ }
+
+ // if we are done processing the maxNumber of lines, break
+ if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
+ break;
+ }
+
+ // see if we've hit our timeout yet
+ /* if ( $the_thing_with_the_stuff ) {
+ do_something( );
+ } */
+ }
+
+ if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
+ $customHeaders = $mapper;
+
+ $customfields = CRM_Core_BAO_CustomField::getFields($this->_contactType);
+ foreach ($customHeaders as $key => $value) {
+ if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
+ $customHeaders[$key] = $customfields[$id][0];
+ }
+ }
+
+ if ($this->_invalidRowCount) {
+ // removed view url for invlaid contacts
+ $headers = array_merge([
+ ts('Line Number'),
+ ts('Reason'),
+ ], $customHeaders);
+ $this->_errorFileName = self::errorFileName(self::ERROR);
+ self::exportCSV($this->_errorFileName, $headers, $this->_errors);
+ }
+ if ($this->_conflictCount) {
+ $headers = array_merge([
+ ts('Line Number'),
+ ts('Reason'),
+ ], $customHeaders);
+ $this->_conflictFileName = self::errorFileName(self::CONFLICT);
+ self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
+ }
+ if ($this->_duplicateCount) {
+ $headers = array_merge([
+ ts('Line Number'),
+ ts('View Contact URL'),
+ ], $customHeaders);
+
+ $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
+ self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
+ }
+ if ($this->_unMatchCount) {
+ $headers = array_merge([
+ ts('Line Number'),
+ ts('Reason'),
+ ], $customHeaders);
+
+ $this->_misMatchFilemName = self::errorFileName(self::NO_MATCH);
+ self::exportCSV($this->_misMatchFilemName, $headers, $this->_unMatch);
+ }
+ if ($this->_unparsedAddressCount) {
+ $headers = array_merge([
+ ts('Line Number'),
+ ts('Contact Edit URL'),
+ ], $customHeaders);
+ $this->_errorFileName = self::errorFileName(self::UNPARSED_ADDRESS_WARNING);
+ self::exportCSV($this->_errorFileName, $headers, $this->_unparsedAddresses);
+ }
+ }
+ //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
+ return $this->fini();
+ }
+
+ /**
+ * Given a list of the importable field keys that the user has selected.
+ * set the active fields array to this list
+ *
+ * @param array $fieldKeys
+ * Mapped array of values.
+ */
+ public function setActiveFields($fieldKeys) {
+ $this->_activeFieldCount = count($fieldKeys);
+ foreach ($fieldKeys as $key) {
+ if (empty($this->_fields[$key])) {
+ $this->_activeFields[] = new CRM_Contact_Import_Field('', ts('- do not import -'));
+ }
+ else {
+ $this->_activeFields[] = clone($this->_fields[$key]);
+ }
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldLocationTypes($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_hasLocationType = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldPhoneTypes($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_phoneType = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldWebsiteTypes($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_websiteType = $elements[$i];
+ }
+ }
+
+ /**
+ * Set IM Service Provider type fields.
+ *
+ * @param array $elements
+ * IM service provider type ids.
+ */
+ public function setActiveFieldImProviders($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_imProvider = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldRelated($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_related = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldRelatedContactType($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_relatedContactType = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldRelatedContactDetails($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_relatedContactDetails = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldRelatedContactLocType($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_relatedContactLocType = $elements[$i];
+ }
+ }
+
+ /**
+ * Set active field for related contact's phone type.
+ *
+ * @param array $elements
+ */
+ public function setActiveFieldRelatedContactPhoneType($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_relatedContactPhoneType = $elements[$i];
+ }
+ }
+
+ /**
+ * @param $elements
+ */
+ public function setActiveFieldRelatedContactWebsiteType($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_relatedContactWebsiteType = $elements[$i];
+ }
+ }
+
+ /**
+ * Set IM Service Provider type fields for related contacts.
+ *
+ * @param array $elements
+ * IM service provider type ids of related contact.
+ */
+ public function setActiveFieldRelatedContactImProvider($elements) {
+ for ($i = 0; $i < count($elements); $i++) {
+ $this->_activeFields[$i]->_relatedContactImProvider = $elements[$i];
+ }
+ }
+
+ /**
+ * Format the field values for input to the api.
+ *
+ * @return array
+ * (reference ) associative array of name/value pairs
+ */
+ public function &getActiveFieldParams() {
+ $params = [];
+
+ for ($i = 0; $i < $this->_activeFieldCount; $i++) {
+ if ($this->_activeFields[$i]->_name == 'do_not_import') {
+ continue;
+ }
+
+ if (isset($this->_activeFields[$i]->_value)) {
+ if (isset($this->_activeFields[$i]->_hasLocationType)) {
+ if (!isset($params[$this->_activeFields[$i]->_name])) {
+ $params[$this->_activeFields[$i]->_name] = [];
+ }
+
+ $value = [
+ $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
+ 'location_type_id' => $this->_activeFields[$i]->_hasLocationType,
+ ];
+
+ if (isset($this->_activeFields[$i]->_phoneType)) {
+ $value['phone_type_id'] = $this->_activeFields[$i]->_phoneType;
+ }
+
+ // get IM service Provider type id
+ if (isset($this->_activeFields[$i]->_imProvider)) {
+ $value['provider_id'] = $this->_activeFields[$i]->_imProvider;
+ }
+
+ $params[$this->_activeFields[$i]->_name][] = $value;
+ }
+ elseif (isset($this->_activeFields[$i]->_websiteType)) {
+ $value = [
+ $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
+ 'website_type_id' => $this->_activeFields[$i]->_websiteType,
+ ];
+
+ $params[$this->_activeFields[$i]->_name][] = $value;
+ }
+
+ if (!isset($params[$this->_activeFields[$i]->_name])) {
+ if (!isset($this->_activeFields[$i]->_related)) {
+ $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value;
+ }
+ }
+
+ //minor fix for CRM-4062
+ if (isset($this->_activeFields[$i]->_related)) {
+ if (!isset($params[$this->_activeFields[$i]->_related])) {
+ $params[$this->_activeFields[$i]->_related] = [];
+ }
+
+ if (!isset($params[$this->_activeFields[$i]->_related]['contact_type']) && !empty($this->_activeFields[$i]->_relatedContactType)) {
+ $params[$this->_activeFields[$i]->_related]['contact_type'] = $this->_activeFields[$i]->_relatedContactType;
+ }
+
+ if (isset($this->_activeFields[$i]->_relatedContactLocType) && !empty($this->_activeFields[$i]->_value)) {
+ if (!empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails]) &&
+ !is_array($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])
+ ) {
+ $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
+ }
+ $value = [
+ $this->_activeFields[$i]->_relatedContactDetails => $this->_activeFields[$i]->_value,
+ 'location_type_id' => $this->_activeFields[$i]->_relatedContactLocType,
+ ];
+
+ if (isset($this->_activeFields[$i]->_relatedContactPhoneType)) {
+ $value['phone_type_id'] = $this->_activeFields[$i]->_relatedContactPhoneType;
+ }
+
+ // get IM service Provider type id for related contact
+ if (isset($this->_activeFields[$i]->_relatedContactImProvider)) {
+ $value['provider_id'] = $this->_activeFields[$i]->_relatedContactImProvider;
+ }
+
+ $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = $value;
+ }
+ elseif (isset($this->_activeFields[$i]->_relatedContactWebsiteType)) {
+ $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = [
+ 'url' => $this->_activeFields[$i]->_value,
+ 'website_type_id' => $this->_activeFields[$i]->_relatedContactWebsiteType,
+ ];
+ }
+ elseif (empty($this->_activeFields[$i]->_value) && isset($this->_activeFields[$i]->_relatedContactLocType)) {
+ if (empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])) {
+ $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
+ }
+ }
+ else {
+ $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = $this->_activeFields[$i]->_value;
+ }
+ }
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * @param string $name
+ * @param $title
+ * @param int $type
+ * @param string $headerPattern
+ * @param string $dataPattern
+ * @param bool $hasLocationType
+ */
+ public function addField(
+ $name, $title, $type = CRM_Utils_Type::T_INT,
+ $headerPattern = '//', $dataPattern = '//',
+ $hasLocationType = FALSE
+ ) {
+ $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
+ if (empty($name)) {
+ $this->_fields['doNotImport'] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
+ }
+ }
+
+ /**
+ * Store parser values.
+ *
+ * @param CRM_Core_Session $store
+ *
+ * @param int $mode
+ */
+ public function set($store, $mode = self::MODE_SUMMARY) {
+ $store->set('rowCount', $this->_rowCount);
+ $store->set('fields', $this->getSelectValues());
+ $store->set('fieldTypes', $this->getSelectTypes());
+
+ $store->set('columnCount', $this->_activeFieldCount);
+
+ $store->set('totalRowCount', $this->_totalCount);
+ $store->set('validRowCount', $this->_validCount);
+ $store->set('invalidRowCount', $this->_invalidRowCount);
+ $store->set('conflictRowCount', $this->_conflictCount);
+ $store->set('unMatchCount', $this->_unMatchCount);
+
+ switch ($this->_contactType) {
+ case 'Individual':
+ $store->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
+ break;
+
+ case 'Household':
+ $store->set('contactType', CRM_Import_Parser::CONTACT_HOUSEHOLD);
+ break;
+
+ case 'Organization':
+ $store->set('contactType', CRM_Import_Parser::CONTACT_ORGANIZATION);
+ }
+
+ if ($this->_invalidRowCount) {
+ $store->set('errorsFileName', $this->_errorFileName);
+ }
+ if ($this->_conflictCount) {
+ $store->set('conflictsFileName', $this->_conflictFileName);
+ }
+ if (isset($this->_rows) && !empty($this->_rows)) {
+ $store->set('dataValues', $this->_rows);
+ }
+
+ if ($this->_unMatchCount) {
+ $store->set('mismatchFileName', $this->_misMatchFilemName);
+ }
+
+ if ($mode == self::MODE_IMPORT) {
+ $store->set('duplicateRowCount', $this->_duplicateCount);
+ $store->set('unparsedAddressCount', $this->_unparsedAddressCount);
+ if ($this->_duplicateCount) {
+ $store->set('duplicatesFileName', $this->_duplicateFileName);
+ }
+ if ($this->_unparsedAddressCount) {
+ $store->set('errorsFileName', $this->_errorFileName);
+ }
+ }
+ //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
+ }
+
+ /**
+ * Export data to a CSV file.
+ *
+ * @param string $fileName
+ * @param array $header
+ * @param array $data
+ */
+ public static function exportCSV($fileName, $header, $data) {
+
+ if (file_exists($fileName) && !is_writable($fileName)) {
+ CRM_Core_Error::movedSiteError($fileName);
+ }
+ //hack to remove '_status', '_statusMsg' and '_id' from error file
+ $errorValues = [];
+ $dbRecordStatus = ['IMPORTED', 'ERROR', 'DUPLICATE', 'INVALID', 'NEW'];
+ foreach ($data as $rowCount => $rowValues) {
+ $count = 0;
+ foreach ($rowValues as $key => $val) {
+ if (in_array($val, $dbRecordStatus) && $count == (count($rowValues) - 3)) {
+ break;
+ }
+ $errorValues[$rowCount][$key] = $val;
+ $count++;
+ }
+ }
+ $data = $errorValues;
+
+ $output = [];
+ $fd = fopen($fileName, 'w');
+
+ foreach ($header as $key => $value) {
+ $header[$key] = "\"$value\"";
+ }
+ $config = CRM_Core_Config::singleton();
+ $output[] = implode($config->fieldSeparator, $header);
+
+ foreach ($data as $datum) {
+ foreach ($datum as $key => $value) {
+ $datum[$key] = "\"$value\"";
+ }
+ $output[] = implode($config->fieldSeparator, $datum);
+ }
+ fwrite($fd, implode("\n", $output));
+ fclose($fd);
+ }
+
+ /**
+ * Update the record with PK $id in the import database table.
+ *
+ * @deprecated - call setImportStatus directly as the parameters are simpler,
+ *
+ * @param int $id
+ * @param array $params
+ */
+ public function updateImportRecord($id, $params): void {
+ $this->setImportStatus((int) $id, $params[$this->_statusFieldName] ?? '', $params["{$this->_statusFieldName}Msg"] ?? '');
+ }
+
+ /**
+ * Set the import status for the given record.
+ *
+ * If this is a sql import then the sql table will be used and the update
+ * will not happen as the relevant fields don't exist in the table - hence
+ * the checks that statusField & primary key are set.
+ *
+ * @param int $id
+ * @param string $status
+ * @param string $message
+ */
+ public function setImportStatus(int $id, string $status, string $message): void {
+ if ($this->_statusFieldName && $this->_primaryKeyName) {
+ CRM_Core_DAO::executeQuery("
+ UPDATE $this->_tableName
+ SET $this->_statusFieldName = %1,
+ {$this->_statusFieldName}Msg = %2
+ WHERE $this->_primaryKeyName = %3
+ ", [
+ 1 => [$status, 'String'],
+ 2 => [$message, 'String'],
+ 3 => [$id, 'Integer'],
+ ]);
+ }
+ }
+
+ /**
+ * Format contact parameters.
+ *
+ * @todo this function needs re-writing & re-merging into the main function.
+ *
+ * Here be dragons.
+ *
+ * @param array $values
+ * @param array $params
+ *
+ * @return bool
+ */
+ protected function formatContactParameters(&$values, &$params) {
+ // Crawl through the possible classes:
+ // Contact
+ // Individual
+ // Household
+ // Organization
+ // Location
+ // Address
+ // Email
+ // Phone
+ // IM
+ // Note
+ // Custom
+
+ // first add core contact values since for other Civi modules they are not added
+ $contactFields = CRM_Contact_DAO_Contact::fields();
+ _civicrm_api3_store_values($contactFields, $values, $params);
+
+ if (isset($values['contact_type'])) {
+ // we're an individual/household/org property
+
+ $fields[$values['contact_type']] = CRM_Contact_DAO_Contact::fields();
+
+ _civicrm_api3_store_values($fields[$values['contact_type']], $values, $params);
+ return TRUE;
+ }
+
+ // Cache the various object fields
+ // @todo - remove this after confirming this is just a compilation of other-wise-cached fields.
+ static $fields = [];
+
+ if (isset($values['individual_prefix'])) {
+ if (!empty($params['prefix_id'])) {
+ $prefixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id');
+ $params['prefix'] = $prefixes[$params['prefix_id']];
+ }
+ else {
+ $params['prefix'] = $values['individual_prefix'];
+ }
+ return TRUE;
+ }
+
+ if (isset($values['individual_suffix'])) {
+ if (!empty($params['suffix_id'])) {
+ $suffixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id');
+ $params['suffix'] = $suffixes[$params['suffix_id']];
+ }
+ else {
+ $params['suffix'] = $values['individual_suffix'];
+ }
+ return TRUE;
+ }
+
+ // CRM-4575
+ if (isset($values['email_greeting'])) {
+ if (!empty($params['email_greeting_id'])) {
+ $emailGreetingFilter = [
+ 'contact_type' => $params['contact_type'] ?? NULL,
+ 'greeting_type' => 'email_greeting',
+ ];
+ $emailGreetings = CRM_Core_PseudoConstant::greeting($emailGreetingFilter);
+ $params['email_greeting'] = $emailGreetings[$params['email_greeting_id']];
+ }
+ else {
+ $params['email_greeting'] = $values['email_greeting'];
+ }
+
+ return TRUE;
+ }
+
+ if (isset($values['postal_greeting'])) {
+ if (!empty($params['postal_greeting_id'])) {
+ $postalGreetingFilter = [
+ 'contact_type' => $params['contact_type'] ?? NULL,
+ 'greeting_type' => 'postal_greeting',
+ ];
+ $postalGreetings = CRM_Core_PseudoConstant::greeting($postalGreetingFilter);
+ $params['postal_greeting'] = $postalGreetings[$params['postal_greeting_id']];
+ }
+ else {
+ $params['postal_greeting'] = $values['postal_greeting'];
+ }
+ return TRUE;
+ }
+
+ if (isset($values['addressee'])) {
+ $params['addressee'] = $values['addressee'];
+ return TRUE;
+ }
+
+ if (isset($values['gender'])) {
+ if (!empty($params['gender_id'])) {
+ $genders = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id');
+ $params['gender'] = $genders[$params['gender_id']];
+ }
+ else {
+ $params['gender'] = $values['gender'];
+ }
+ return TRUE;
+ }
+
+ if (!empty($values['preferred_communication_method'])) {
+ $comm = [];
+ $pcm = array_change_key_case(array_flip(CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method')), CASE_LOWER);
+
+ $preffComm = explode(',', $values['preferred_communication_method']);
+ foreach ($preffComm as $v) {
+ $v = strtolower(trim($v));
+ if (array_key_exists($v, $pcm)) {
+ $comm[$pcm[$v]] = 1;
+ }
+ }
+
+ $params['preferred_communication_method'] = $comm;
+ return TRUE;
+ }
+
+ // format the website params.
+ if (!empty($values['url'])) {
+ static $websiteFields;
+ if (!is_array($websiteFields)) {
+ $websiteFields = CRM_Core_DAO_Website::fields();
+ }
+ if (!array_key_exists('website', $params) ||
+ !is_array($params['website'])
+ ) {
+ $params['website'] = [];
+ }
+
+ $websiteCount = count($params['website']);
+ _civicrm_api3_store_values($websiteFields, $values,
+ $params['website'][++$websiteCount]
+ );
+
+ return TRUE;
+ }
+
+ if (isset($values['note'])) {
+ // add a note field
+ if (!isset($params['note'])) {
+ $params['note'] = [];
+ }
+ $noteBlock = count($params['note']) + 1;
+
+ $params['note'][$noteBlock] = [];
+ if (!isset($fields['Note'])) {
+ $fields['Note'] = CRM_Core_DAO_Note::fields();
+ }
+
+ // get the current logged in civicrm user
+ $session = CRM_Core_Session::singleton();
+ $userID = $session->get('userID');
+
+ if ($userID) {
+ $values['contact_id'] = $userID;
+ }
+
+ _civicrm_api3_store_values($fields['Note'], $values, $params['note'][$noteBlock]);
+
+ return TRUE;
+ }
+
+ // Check for custom field values
+ $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $values),
+ FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE
+ );
+
+ foreach ($values as $key => $value) {
+ if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
+ // check if it's a valid custom field id
+
+ if (!array_key_exists($customFieldID, $customFields)) {
+ return civicrm_api3_create_error('Invalid custom field ID');
+ }
+ else {
+ $params[$key] = $value;
+ }
+ }
+ }
+ return TRUE;
+ }
+
+ /**
+ * Format location block ready for importing.
+ *
+ * There is some test coverage for this in CRM_Contact_Import_Parser_ContactTest
+ * e.g. testImportPrimaryAddress.
+ *
+ * @param array $values
+ * @param array $params
+ *
+ * @return bool
+ */
+ protected function formatLocationBlock(&$values, &$params) {
+ $blockTypes = [
+ 'phone' => 'Phone',
+ 'email' => 'Email',
+ 'im' => 'IM',
+ 'openid' => 'OpenID',
+ 'phone_ext' => 'Phone',
+ ];
+ foreach ($blockTypes as $blockFieldName => $block) {
+ if (!array_key_exists($blockFieldName, $values)) {
+ continue;
+ }
+ $blockIndex = $values['location_type_id'] . (!empty($values['phone_type_id']) ? '_' . $values['phone_type_id'] : '');
+
+ // block present in value array.
+ if (!array_key_exists($blockFieldName, $params) || !is_array($params[$blockFieldName])) {
+ $params[$blockFieldName] = [];
+ }
+
+ $fields[$block] = $this->getMetadataForEntity($block);
+
+ // copy value to dao field name.
+ if ($blockFieldName == 'im') {
+ $values['name'] = $values[$blockFieldName];
+ }
+
+ _civicrm_api3_store_values($fields[$block], $values,
+ $params[$blockFieldName][$blockIndex]
+ );
+
+ $this->fillPrimary($params[$blockFieldName][$blockIndex], $values, $block, CRM_Utils_Array::value('id', $params));
+
+ if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
+ $params[$blockFieldName][$blockIndex]['is_primary'] = TRUE;
+ }
+
+ // we only process single block at a time.
+ return TRUE;
+ }
+
+ // handle address fields.
+ if (!array_key_exists('address', $params) || !is_array($params['address'])) {
+ $params['address'] = [];
+ }
+
+ // Note: we doing multiple value formatting here for address custom fields, plus putting into right format.
+ // The actual formatting (like date, country ..etc) for address custom fields is taken care of while saving
+ // the address in CRM_Core_BAO_Address::create method
+ if (!empty($values['location_type_id'])) {
+ static $customFields = [];
+ if (empty($customFields)) {
+ $customFields = CRM_Core_BAO_CustomField::getFields('Address');
+ }
+ // make a copy of values, as we going to make changes
+ $newValues = $values;
+ foreach ($values as $key => $val) {
+ $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key);
+ if ($customFieldID && array_key_exists($customFieldID, $customFields)) {
+
+ $htmlType = $customFields[$customFieldID]['html_type'] ?? NULL;
+ if (CRM_Core_BAO_CustomField::isSerialized($customFields[$customFieldID]) && $val) {
+ $mulValues = explode(',', $val);
+ $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE);
+ $newValues[$key] = [];
+ foreach ($mulValues as $v1) {
+ foreach ($customOption as $v2) {
+ if ((strtolower($v2['label']) == strtolower(trim($v1))) ||
+ (strtolower($v2['value']) == strtolower(trim($v1)))
+ ) {
+ if ($htmlType == 'CheckBox') {
+ $newValues[$key][$v2['value']] = 1;
+ }
+ else {
+ $newValues[$key][] = $v2['value'];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // consider new values
+ $values = $newValues;
+ }
+
+ $fields['Address'] = $this->getMetadataForEntity('Address');
+ // @todo this is kinda replicated below....
+ _civicrm_api3_store_values($fields['Address'], $values, $params['address'][$values['location_type_id']]);
+
+ $addressFields = [
+ 'county',
+ 'country',
+ 'state_province',
+ 'supplemental_address_1',
+ 'supplemental_address_2',
+ 'supplemental_address_3',
+ 'StateProvince.name',
+ ];
+ foreach (array_keys($customFields) as $customFieldID) {
+ $addressFields[] = 'custom_' . $customFieldID;
+ }
+
+ foreach ($addressFields as $field) {
+ if (array_key_exists($field, $values)) {
+ if (!array_key_exists('address', $params)) {
+ $params['address'] = [];
+ }
+ $params['address'][$values['location_type_id']][$field] = $values[$field];
+ }
+ }
+
+ $this->fillPrimary($params['address'][$values['location_type_id']], $values, 'address', CRM_Utils_Array::value('id', $params));
+ return TRUE;
+ }
+
+ /**
+ * Get the field metadata for the relevant entity.
+ *
+ * @param string $entity
+ *
+ * @return array
+ */
+ protected function getMetadataForEntity($entity) {
+ if (!isset($this->fieldMetadata[$entity])) {
+ $className = "CRM_Core_DAO_$entity";
+ $this->fieldMetadata[$entity] = $className::fields();
+ }
+ return $this->fieldMetadata[$entity];
+ }
+
+ /**
+ * Fill in the primary location.
+ *
+ * If the contact has a primary address we update it. Otherwise
+ * we add an address of the default location type.
+ *
+ * @param array $params
+ * Address block parameters
+ * @param array $values
+ * Input values
+ * @param string $entity
+ * - address, email, phone
+ * @param int|null $contactID
+ *
+ * @throws \CiviCRM_API3_Exception
+ */
+ protected function fillPrimary(&$params, $values, $entity, $contactID) {
+ if ($values['location_type_id'] === 'Primary') {
+ if ($contactID) {
+ $primary = civicrm_api3($entity, 'get', [
+ 'return' => 'location_type_id',
+ 'contact_id' => $contactID,
+ 'is_primary' => 1,
+ 'sequential' => 1,
+ ]);
+ }
+ $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
+ $params['location_type_id'] = (int) (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
+ $params['is_primary'] = 1;
+ }
+ }
+
}
*
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
- * $Id: $
- *
*/
/**
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+
+/**
+ * This class contains user jobs functionality.
+ */
+class CRM_Core_BAO_UserJob extends CRM_Core_DAO_UserJob {
+
+ /**
+ * Get the statuses for Import Jobs.
+ *
+ * @return array
+ */
+ public static function getStatuses(): array {
+ return [
+ [
+ 'id' => 1,
+ 'name' => 'completed',
+ 'label' => ts('Completed'),
+ ],
+ [
+ 'id' => 2,
+ 'name' => 'scheduled',
+ 'label' => ts('Scheduled'),
+ ],
+ [
+ 'id' => 3,
+ 'name' => 'in_progress',
+ 'label' => ts('In Progress'),
+ ],
+ ];
+ }
+
+ /**
+ * Get the types Import Jobs.
+ *
+ * This is largely a placeholder at this stage. It will likely wind
+ * up as an option value so extensions can add different types.
+ *
+ * However, for now it just holds the one type being worked on.
+ *
+ * @return array
+ */
+ public static function getTypes(): array {
+ return [
+ [
+ 'id' => 1,
+ 'name' => 'contact_import',
+ 'label' => ts('Contact Import'),
+ ],
+ ];
+ }
+
+}
'class' => 'CRM_Core_DAO_UFMatch',
'table' => 'civicrm_uf_match',
],
+ 'CRM_Core_DAO_UserJob' => [
+ 'name' => 'UserJob',
+ 'class' => 'CRM_Core_DAO_UserJob',
+ 'table' => 'civicrm_user_job',
+ ],
'CRM_Core_DAO_Timezone' => [
'name' => 'Timezone',
'class' => 'CRM_Core_DAO_Timezone',
--- /dev/null
+<?php
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ *
+ * Generated from xml/schema/CRM/Core/UserJob.xml
+ * DO NOT EDIT. Generated by CRM_Core_CodeGen
+ * (GenCodeChecksum:58e6fcaa028d157bfa074a073111239d)
+ */
+
+/**
+ * Database access object for the UserJob entity.
+ */
+class CRM_Core_DAO_UserJob extends CRM_Core_DAO {
+ const EXT = 'civicrm';
+ const TABLE_ADDED = '5.50';
+
+ /**
+ * Static instance to hold the table name.
+ *
+ * @var string
+ */
+ public static $_tableName = 'civicrm_user_job';
+
+ /**
+ * Should CiviCRM log any modifications to this table in the civicrm_log table.
+ *
+ * @var bool
+ */
+ public static $_log = FALSE;
+
+ /**
+ * Job ID
+ *
+ * @var int|string|null
+ * (SQL type: int unsigned)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $id;
+
+ /**
+ * Unique name for job.
+ *
+ * @var string|null
+ * (SQL type: varchar(64))
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $name;
+
+ /**
+ * FK to contact table.
+ *
+ * @var int|string|null
+ * (SQL type: int unsigned)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $created_id;
+
+ /**
+ * Date and time this job was created.
+ *
+ * @var string
+ * (SQL type: timestamp)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $created_date;
+
+ /**
+ * Date and time this import job started.
+ *
+ * @var string
+ * (SQL type: timestamp)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $start_date;
+
+ /**
+ * Date and time this import job ended.
+ *
+ * @var string
+ * (SQL type: timestamp)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $end_date;
+
+ /**
+ * Date and time to clean up after this import job (temp table deletion date).
+ *
+ * @var string
+ * (SQL type: timestamp)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $expires_date;
+
+ /**
+ * @var int|string
+ * (SQL type: int unsigned)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $status_id;
+
+ /**
+ * @var int|string
+ * (SQL type: int unsigned)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $type_id;
+
+ /**
+ * FK to Queue
+ *
+ * @var int|string|null
+ * (SQL type: int unsigned)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $queue_id;
+
+ /**
+ * Data pertaining to job configuration
+ *
+ * @var string|null
+ * (SQL type: text)
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $metadata;
+
+ /**
+ * Class constructor.
+ */
+ public function __construct() {
+ $this->__table = 'civicrm_user_job';
+ parent::__construct();
+ }
+
+ /**
+ * Returns localized title of this entity.
+ *
+ * @param bool $plural
+ * Whether to return the plural version of the title.
+ */
+ public static function getEntityTitle($plural = FALSE) {
+ return $plural ? ts('User Jobs') : ts('User Job');
+ }
+
+ /**
+ * Returns foreign keys and entity references.
+ *
+ * @return array
+ * [CRM_Core_Reference_Interface]
+ */
+ public static function getReferenceColumns() {
+ if (!isset(Civi::$statics[__CLASS__]['links'])) {
+ Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__);
+ Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), 'created_id', 'civicrm_contact', 'id');
+ Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), 'queue_id', 'civicrm_queue', 'id');
+ CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', Civi::$statics[__CLASS__]['links']);
+ }
+ return Civi::$statics[__CLASS__]['links'];
+ }
+
+ /**
+ * Returns all the column names of this table
+ *
+ * @return array
+ */
+ public static function &fields() {
+ if (!isset(Civi::$statics[__CLASS__]['fields'])) {
+ Civi::$statics[__CLASS__]['fields'] = [
+ 'id' => [
+ 'name' => 'id',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'title' => ts('User Job ID'),
+ 'description' => ts('Job ID'),
+ 'required' => TRUE,
+ 'where' => 'civicrm_user_job.id',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'type' => 'Number',
+ ],
+ 'readonly' => TRUE,
+ 'add' => '5.50',
+ ],
+ 'name' => [
+ 'name' => 'name',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'title' => ts('User job name'),
+ 'description' => ts('Unique name for job.'),
+ 'maxlength' => 64,
+ 'size' => CRM_Utils_Type::BIG,
+ 'where' => 'civicrm_user_job.name',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'add' => '5.50',
+ ],
+ 'created_id' => [
+ 'name' => 'created_id',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'title' => ts('Created By Contact ID'),
+ 'description' => ts('FK to contact table.'),
+ 'where' => 'civicrm_user_job.created_id',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'FKClassName' => 'CRM_Contact_DAO_Contact',
+ 'html' => [
+ 'label' => ts("Created By"),
+ ],
+ 'add' => '5.50',
+ ],
+ 'created_date' => [
+ 'name' => 'created_date',
+ 'type' => CRM_Utils_Type::T_TIMESTAMP,
+ 'title' => ts('Import Job Created Date'),
+ 'description' => ts('Date and time this job was created.'),
+ 'required' => TRUE,
+ 'where' => 'civicrm_user_job.created_date',
+ 'default' => 'CURRENT_TIMESTAMP',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
+ ],
+ 'readonly' => TRUE,
+ 'add' => '5.50',
+ ],
+ 'start_date' => [
+ 'name' => 'start_date',
+ 'type' => CRM_Utils_Type::T_TIMESTAMP,
+ 'title' => ts('Import Job Started Date'),
+ 'description' => ts('Date and time this import job started.'),
+ 'required' => FALSE,
+ 'where' => 'civicrm_user_job.start_date',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
+ ],
+ 'readonly' => TRUE,
+ 'add' => '5.50',
+ ],
+ 'end_date' => [
+ 'name' => 'end_date',
+ 'type' => CRM_Utils_Type::T_TIMESTAMP,
+ 'title' => ts('Job Ended Date'),
+ 'description' => ts('Date and time this import job ended.'),
+ 'required' => FALSE,
+ 'where' => 'civicrm_user_job.end_date',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
+ ],
+ 'add' => '5.50',
+ ],
+ 'expires_date' => [
+ 'name' => 'expires_date',
+ 'type' => CRM_Utils_Type::T_TIMESTAMP,
+ 'title' => ts('Import Job Expires Date'),
+ 'description' => ts('Date and time to clean up after this import job (temp table deletion date).'),
+ 'required' => FALSE,
+ 'where' => 'civicrm_user_job.expires_date',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
+ ],
+ 'add' => '5.50',
+ ],
+ 'status_id' => [
+ 'name' => 'status_id',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'title' => ts('User Job Status ID'),
+ 'required' => TRUE,
+ 'where' => 'civicrm_user_job.status_id',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'label' => ts("Job Status"),
+ ],
+ 'pseudoconstant' => [
+ 'callback' => 'CRM_Core_BAO_UserJob::getStatuses',
+ ],
+ 'add' => '5.50',
+ ],
+ 'type_id' => [
+ 'name' => 'type_id',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'title' => ts('User Job Type ID'),
+ 'required' => TRUE,
+ 'where' => 'civicrm_user_job.type_id',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'html' => [
+ 'label' => ts("Job Type"),
+ ],
+ 'pseudoconstant' => [
+ 'callback' => 'CRM_Core_BAO_UserJob::getTypes',
+ ],
+ 'add' => '5.50',
+ ],
+ 'queue_id' => [
+ 'name' => 'queue_id',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'title' => ts('Queue ID'),
+ 'description' => ts('FK to Queue'),
+ 'where' => 'civicrm_user_job.queue_id',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'FKClassName' => 'CRM_Queue_DAO_Queue',
+ 'html' => [
+ 'label' => ts("Queue"),
+ ],
+ 'add' => NULL,
+ ],
+ 'metadata' => [
+ 'name' => 'metadata',
+ 'type' => CRM_Utils_Type::T_TEXT,
+ 'title' => ts('Job metadata'),
+ 'description' => ts('Data pertaining to job configuration'),
+ 'where' => 'civicrm_user_job.metadata',
+ 'table_name' => 'civicrm_user_job',
+ 'entity' => 'UserJob',
+ 'bao' => 'CRM_Core_BAO_UserJob',
+ 'localizable' => 0,
+ 'serialize' => self::SERIALIZE_JSON,
+ 'add' => '5.50',
+ ],
+ ];
+ CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']);
+ }
+ return Civi::$statics[__CLASS__]['fields'];
+ }
+
+ /**
+ * Return a mapping from field-name to the corresponding key (as used in fields()).
+ *
+ * @return array
+ * Array(string $name => string $uniqueName).
+ */
+ public static function &fieldKeys() {
+ if (!isset(Civi::$statics[__CLASS__]['fieldKeys'])) {
+ Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(CRM_Utils_Array::collect('name', self::fields()));
+ }
+ return Civi::$statics[__CLASS__]['fieldKeys'];
+ }
+
+ /**
+ * Returns the names of this table
+ *
+ * @return string
+ */
+ public static function getTableName() {
+ return self::$_tableName;
+ }
+
+ /**
+ * Returns if this table needs to be logged
+ *
+ * @return bool
+ */
+ public function getLog() {
+ return self::$_log;
+ }
+
+ /**
+ * Returns the list of fields that can be imported
+ *
+ * @param bool $prefix
+ *
+ * @return array
+ */
+ public static function &import($prefix = FALSE) {
+ $r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'user_job', $prefix, []);
+ return $r;
+ }
+
+ /**
+ * Returns the list of fields that can be exported
+ *
+ * @param bool $prefix
+ *
+ * @return array
+ */
+ public static function &export($prefix = FALSE) {
+ $r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'user_job', $prefix, []);
+ return $r;
+ }
+
+ /**
+ * Returns the list of indices
+ *
+ * @param bool $localize
+ *
+ * @return array
+ */
+ public static function indices($localize = TRUE) {
+ $indices = [
+ 'UI_name' => [
+ 'name' => 'UI_name',
+ 'field' => [
+ 0 => 'name',
+ ],
+ 'localizable' => FALSE,
+ 'unique' => TRUE,
+ 'sig' => 'civicrm_user_job::1::name',
+ ],
+ ];
+ return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
+ }
+
+}
ts('Reason'),
], $customHeaders);
$this->_errorFileName = self::errorFileName(self::ERROR);
- CRM_Contact_Import_Parser::exportCSV($this->_errorFileName, $headers, $this->_errors);
+ CRM_Contact_Import_Parser_Contact::exportCSV($this->_errorFileName, $headers, $this->_errors);
}
if ($this->_conflictCount) {
$headers = array_merge([
ts('Reason'),
], $customHeaders);
$this->_conflictFileName = self::errorFileName(self::CONFLICT);
- CRM_Contact_Import_Parser::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
+ CRM_Contact_Import_Parser_Contact::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
}
if ($this->_duplicateCount) {
$headers = array_merge([
], $customHeaders);
$this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
- CRM_Contact_Import_Parser::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
+ CRM_Contact_Import_Parser_Contact::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
}
}
return $this->fini();
}
/**
- * Adapted from CRM_Contact_Import_Parser::formatCommonData
+ * Adapted from CRM_Contact_Import_Parser_Contact::formatCommonData
*
* TODO: Is this function even necessary? All values get passed to the api anyway.
*
$this->_params[0]['is_pay_later'] = $this->get('is_pay_later');
$this->assign('is_pay_later', $this->_params[0]['is_pay_later']);
- if ($this->_params[0]['is_pay_later']) {
- $this->assign('pay_later_receipt', $this->_values['event']['pay_later_receipt']);
- }
+ $this->assign('pay_later_receipt', $this->_params[0]['is_pay_later'] ? $this->_values['event']['pay_later_receipt'] : NULL);
CRM_Utils_Hook::eventDiscount($this, $this->_params);
$this->assign('context', $context);
if ($this->membershipID) {
- $params = ['id' => $this->membershipID];
- CRM_Member_BAO_Membership::retrieve($params, $values);
+ $values = \Civi\Api4\Membership::get()
+ ->addSelect('*', 'status_id:label', 'membership_type_id:label', 'membership_type_id.financial_type_id', 'status_id.is_current_member')
+ ->addWhere('id', '=', $this->membershipID)
+ ->execute()
+ ->first();
+
+ // Ensure keys expected by MembershipView.tpl are set correctly
+ // Some of these defaults are overwritten dependant on context below
+ $values['financialTypeId'] = $values['membership_type_id.financial_type_id'];
+ $values['membership_type'] = $values['membership_type_id:label'];
+ $values['status'] = $values['status_id:label'];
+ $values['active'] = $values['status_id.is_current_member'];
+ $values['owner_contact_id'] = FALSE;
+ $values['owner_display_name'] = FALSE;
+ $values['campaign'] = FALSE;
+
if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
$finTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'financial_type_id');
$finType = CRM_Contribute_PseudoConstant::financialType($finTypeId);
$memberships = civicrm_api3('membership', 'get', [
'id' => ['IN' => $this->_memberIds],
'return' => 'contact_id',
+ 'options' => ['limit' => 0],
]);
foreach ($memberships['values'] as $id => $membership) {
if (isset($rows[$membership['contact_id']])) {
{* file to handle db changes in 5.50.alpha1 during upgrade *}
+
+CREATE TABLE `civicrm_user_job` (
+`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Job ID',
+`name` varchar(64) COMMENT 'Unique name for job.',
+`created_id` int unsigned COMMENT 'FK to contact table.',
+`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date and time this job was created.',
+`start_date` timestamp NULL COMMENT 'Date and time this import job started.',
+`end_date` timestamp NULL COMMENT 'Date and time this import job ended.',
+`expires_date` timestamp NULL COMMENT 'Date and time to clean up after this import job (temp table deletion date).',
+`status_id` int unsigned NOT NULL,
+`type_id` int unsigned NOT NULL,
+`queue_id` int unsigned COMMENT 'FK to Queue',
+`metadata` text COMMENT 'Data pertaining to job configuration',
+PRIMARY KEY (`id`),
+UNIQUE INDEX `UI_name`(name),
+CONSTRAINT FK_civicrm_user_job_created_id FOREIGN KEY (`created_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE SET NULL,
+CONSTRAINT FK_civicrm_user_job_queue_id FOREIGN KEY (`queue_id`) REFERENCES `civicrm_queue`(`id`) ON DELETE SET NULL
+)
+ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+namespace Civi\Api4;
+
+/**
+ * UserJob entity.
+ *
+ * This entity allows tracking of imports, including associated temp tables.
+ *
+ * @searchable secondary
+ * @since 5.50
+ * @package Civi\Api4
+ */
+class UserJob extends Generic\DAOEntity {
+
+}
$container->setDefinition('pear_mail', new Definition('Mail'))
->setFactory('CRM_Utils_Mail::createMailer')->setPublic(TRUE);
- $container->setDefinition('crypto.registry', new Definition('Civi\Crypto\CryptoService'))
+ $container->setDefinition('crypto.registry', new Definition('Civi\Crypto\CryptoRegistry'))
->setFactory('Civi\Crypto\CryptoRegistry::createDefaultRegistry')->setPublic(TRUE);
$container->setDefinition('crypto.token', new Definition('Civi\Crypto\CryptoToken', []))
* @throws \CRM_Core_Exception
* @throws \Civi\Crypto\Exception\CryptoException
*/
- public static function createDefaultRegistry() {
+ public static function createDefaultRegistry(): CryptoRegistry {
$registry = new static();
$registry->addCipherSuite(new \Civi\Crypto\PhpseclibCipherSuite());
<td class="crm-acl_entity_role-acl_role">{$row.acl_role}</td>
<td class="crm-acl_entity_role-entity">{$row.entity}</td>
<td class="crm-acl_entity_role-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</tbody>
<td>
{if (!empty($row.id))}
- {$row.action|replace:'xx':$row.id}
+ {$row.action|smarty:nodefaults|replace:'xx':$row.id}
{else}
{$row.action}
{/if}
<td class="crm-activity-date_time">{$row.activity_date_time|crmDate}</td>
<td class="crm-activity-status crm-activity-status_{$row.status_id}">{$row.status}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
<p>{ts 1=$docLink}ACLs (Access Control Lists) allow you control access to CiviCRM data. An ACL consists of an <strong>Operation</strong> (e.g. 'View' or 'Edit'), a <strong>set of Data</strong> that the operation can be performed on (e.g. a group of contacts), and a <strong>Role</strong> that has permission to do this operation. Refer to the %1 for more info.{/ts}
{if $config->userSystem->is_drupal EQ '1'}{ts}Note that a CiviCRM ACL Role is not related to the Drupal Role.{/ts}{/if}</p>
<p>{ts}<strong>EXAMPLE:</strong> 'Team Leaders' (<em>ACL Role</em>) can 'Edit' (<em>Operation</em>) all contacts in the 'Active Volunteers Group' (<em>Data</em>).{/ts}</p>
- <p>{ts 1=$ufAccessURL 2=$jAccessParams 3=$config->userFramework}Use <a href='%1' %2>%3 Access Control</a> to manage basic access to CiviCRM components and menu items. Use CiviCRM ACLs to control access to specific CiviCRM contact groups. You can also configure ACLs to grant or deny access to specific Events, Profiles, and/or Custom Data Fields.{/ts}</p>
+ <p>{ts 1=$ufAccessURL|smarty:nodefaults 2=$jAccessParams 3=$config->userFramework}Use <a href='%1' %2>%3 Access Control</a> to manage basic access to CiviCRM components and menu items. Use CiviCRM ACLs to control access to specific CiviCRM contact groups. You can also configure ACLs to grant or deny access to specific Events, Profiles, and/or Custom Data Fields.{/ts}</p>
<p>{ts 1=$config->userFramework}Note that %1 Access Control permissions take precedence over CiviCRM ACLs. If you wish to use CiviCRM ACLs, first disable the related permission in %1 Access control for a user role, and then gradually add ACLs to replace that permission for certain groups of contacts.{/ts}
</div>
<table class="report">
<tr>
- <td class="nowrap"><a href="{$ufAccessURL}" {$jAccessParams} id="adminAccess"><i class="crm-i fa-chevron-right fa-fw" aria-hidden="true"></i> {ts 1=$config->userFramework}%1 Access Control{/ts}</a></td>
+ <td class="nowrap"><a href="{$ufAccessURL|smarty:nodefaults}" {$jAccessParams} id="adminAccess"><i class="crm-i fa-chevron-right fa-fw" aria-hidden="true"></i> {ts 1=$config->userFramework}%1 Access Control{/ts}</a></td>
<td>{ts}Grant access to CiviCRM components and other CiviCRM permissions.{/ts}</td>
</tr>
<tr><td colspan="2" class="separator"><strong>{ts}Use following steps if you need to control View and/or Edit permissions for specific contact groups, specific profiles or specific custom data fields.{/ts}</strong></td></tr>
<td class="crm-contactType-label crm-editable" data-field="label">{ts}{$row.label}{/ts}</td>
<td class="crm-contactType-parent">{if $row.parent}{ts}{$row.parent_label}{/ts}{else}{ts}(built-in){/ts}{/if}</td>
<td class="crm-contactType-description crm-editable" data-field="description" data-type="textarea">{$row.description}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-event-is_monetary">{if $row.is_monetary eq 1}{ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crm-event-is_online_registration">{if $row.is_online_registration eq 1}{ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crm-event-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td class="crm-event-action">{$row.action|replace:'xx':$row.id}</td>
+ <td class="crm-event-action">{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
</td>
<td class="crm-extensions-version">{$row.version|escape}</td>
<td class="crm-extensions-description">{$row.type|capitalize}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
<tr class="hiddenElement" id="crm-extensions-details-addnew-{$row.file}">
<td>
{/if}
</td>
<td class="crm-extensions-description">{$row.type|escape|capitalize}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
<tr class="hiddenElement" id="crm-extensions-details-{$row.file|escape}">
<td>
<td class="crm-job-name">{if $row.parameters eq null}<em>{ts}no parameters{/ts}</em>{else}<pre>{$row.parameters}</pre>{/if}</td>
<td class="crm-job-name">{if $row.last_run eq null}never{else}{$row.last_run|crmDate:$config->dateformatDatetime}{/if}</td>
<td id="row_{$row.id}_status" class="crm-job-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-labelFormat-is_default">{icon condition=$row.is_default}{ts}Default{/ts}{/icon} </td>
<td class="crm-labelFormat-is_reserved">{if $row.is_reserved eq 1}{ts}Yes{/ts}{else}{ts}No{/ts}{/if}
</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crmf-description crm-editable">{$row.description}</td>
<td id="row_{$row.id}_status" class="crmf-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crmf-is_default">{if $row.is_default}{icon condition=$row.is_default}{ts}Default{/ts}{/icon} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<!--<td>{$row.port}</td>-->
<td class="crm-mailSettings-is_ssl">{if $row.is_ssl eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crm-mailSettings-is_default">{if $row.is_default eq 1}{ts}Bounce Processing <strong>(Default)</strong>{/ts}{else}{ts}Email-to-Activity{/ts}{/if} </td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-mapping-name">{$row.name}</td>
<td class="crm-mapping-description">{$row.description}</td>
<td class="crm-mapping-mapping_type">{$row.mapping_type}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{$row.msg_subject}</td>
<td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
{/if}
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</tbody>
{/if}
<td class="crm-admin-options-is_reserved">{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crm-admin-options-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</tbody>
<td class="center crmf-is_counted">{icon condition=$row.is_counted}{ts}Counted{/ts}{/icon}</td>
<td class="crmf-weight">{$row.weight|smarty:nodefaults}</td>
<td class="crmf-visibility">{$row.visibility}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crmf-is_active center">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crmf-is_default center">{icon condition=$row.is_default}{ts}Default{/ts}{/icon}
</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-pdfFormat-description">{$row.description}</td>
<td class="crm-pdfFormat-is_default">{icon condition=$row.is_default}{ts}Default{/ts}{/icon} </td>
<td class="crm-pdfFormat-order nowrap">{$row.weight|smarty:nodefaults}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="nowrap">{if !$row.date_format}{ts}Default{/ts}{else}{$row.date_format}{/if}</td>
<td align="right">{$row.start}</td>
<td align="right">{$row.end}</td>
- <td><span>{$row.action|replace:'xx':$row.id}</span></td>
+ <td><span>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</span></td>
</tr>
{/foreach}
</table>
{if $row.contact_type_b_display} {$row.contact_type_b_display}
{if !empty($row.contact_sub_type_b)} - {$row.contact_sub_type_b}{/if} {else} {ts}All Contacts{/ts} {/if} </td>
<td class="crm-relationship-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-scheduleReminders-title">{$row.status}</td>
<td class="crm-scheduleReminders-is_repeat">{if $row.is_repeat eq 1}{ts}Yes{/ts}{else}{ts}No{/ts}{/if} </td>
<td id="row_{$row.id}_status" class="crm-scheduleReminders-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
<td class="hiddenElement"></td>
</tr>
{/foreach}
</td>
<td class="crm-badge-layout-is_default">{icon condition=$row.is_default}{ts}Default{/ts}{/icon}
</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="nowrap crm-admin-options-order">{$row.weight|smarty:nodefaults}</td>
<td class="crm-admin-options-is_reserved">{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crm-admin-options-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
call_user_func(array('CRM_Core_Permission','check'), 'add cases') ) AND
$allowToAddNewCase}
<div class="action-link">
- <a accesskey="N" href="{$newCaseURL}" class="button no-popup"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Case{/ts}</span></a>
+ <a accesskey="N" href="{$newCaseURL|smarty:nodefaults}" class="button no-popup"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Case{/ts}</span></a>
</div>
{/if}
<tr class="{cycle values="odd-row,even-row"}">
<td>{$row.title}</td>
<td>{$row.used_display}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{if $row.is_deductible eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-contribution-form-block-cost">{$row.cost|crmMoney}</td>
<td class="crm-contribution-form-block-financial_type">{$row.financial_type}</td>
<td id="row_{$row.id}_status" >{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td id={$row.id}>{$row.action|replace:'xx':$row.id}</td>
+ <td id={$row.id}>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<div class="help">
{if $permission EQ 'edit'}
{capture assign=newContribURL}{crmURL p="civicrm/contact/view/contribution" q="reset=1&action=add&cid=`$contactId`&context=contribution"}{/capture}
- {capture assign=link}class="action-item" href="{$newContribURL}"{/capture}
- {ts 1=$link}Click <a %1>Record Contribution</a> to record a new contribution received from this contact.{/ts}
+ {capture assign=link}class="action-item" href="{$newContribURL|smarty:nodefaults}"{/capture}
+ {ts 1=$link|smarty:nodefaults}Click <a %1>Record Contribution</a> to record a new contribution received from this contact.{/ts}
{if $newCredit}
{capture assign=newCreditURL}{crmURL p="civicrm/contact/view/contribution" q="reset=1&action=add&cid=`$contactId`&context=contribution&mode=live"}{/capture}
- {capture assign=link}class="action-item" href="{$newCreditURL}"{/capture}
- {ts 1=$link}Click <a %1>Submit Credit Card Contribution</a> to process a new contribution on behalf of the contributor using their credit card.{/ts}
+ {capture assign=link}class="action-item" href="{$newCreditURL|smarty:nodefaults}"{/capture}
+ {ts 1=$link|smarty:nodefaults}Click <a %1>Submit Credit Card Contribution</a> to process a new contribution on behalf of the contributor using their credit card.{/ts}
{/if}
{else}
{ts 1=$displayName}Contributions received from %1 since inception.{/ts}
{if $action eq 16 and $permission EQ 'edit'}
<div class="action-link">
- <a accesskey="N" href="{$newContribURL}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Record Contribution (Check, Cash, EFT ...){/ts}</span></a>
+ <a accesskey="N" href="{$newContribURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Record Contribution (Check, Cash, EFT ...){/ts}</span></a>
{if $newCredit}
- <a accesskey="N" href="{$newCreditURL}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Contribution{/ts}</span></a>
+ <a accesskey="N" href="{$newCreditURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Contribution{/ts}</span></a>
{/if}
<br /><br />
</div>
<div class="help">
<p>{ts 1=$displayName}This page lists all event registrations for %1 since inception.{/ts}
- {capture assign="link"}class="action-item" href="{$newEventURL}"{/capture}
- {if $permission EQ 'edit'}{ts 1=$link}Click <a %1>Add Event Registration</a> to register this contact for an event.{/ts}{/if}
+ {capture assign="link"}class="action-item" href="{$newEventURL|smarty:nodefaults}"{/capture}
+ {if $permission EQ 'edit'}{ts 1=$link|smarty:nodefaults}Click <a %1>Add Event Registration</a> to register this contact for an event.{/ts}{/if}
{if $accessContribution and $newCredit}
{capture assign=newCreditURL}{crmURL p="civicrm/contact/view/participant" q="reset=1&action=add&cid=`$contactId`&context=participant&mode=live"}{/capture}
- {capture assign="link"}class="action-item" href="{$newCreditURL}"{/capture}
- {ts 1=$link}Click <a %1>Submit Credit Card Event Registration</a> to process a new New Registration on behalf of the participant using their credit card.{/ts}
+ {capture assign="link"}class="action-item" href="{$newCreditURL|smarty:nodefaults}"{/capture}
+ {ts 1=$link|smarty:nodefaults}Click <a %1>Submit Credit Card Event Registration</a> to process a new New Registration on behalf of the participant using their credit card.{/ts}
{/if}
</p>
</div>
{if $action eq 16 and $permission EQ 'edit'}
<div class="action-link">
- <a accesskey="N" href="{$newEventURL}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Event Registration{/ts}</span></a>
+ <a accesskey="N" href="{$newEventURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Event Registration{/ts}</span></a>
{if $accessContribution and $newCredit}
- <a accesskey="N" href="{$newCreditURL}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Event Registration{/ts}</a></span>
+ <a accesskey="N" href="{$newCreditURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Event Registration{/ts}</a></span>
{/if}
- <br/ ><br/ >
+ <br/><br/>
</div>
{/if}
<td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td>{icon condition=$row.is_default}{ts}Default{/ts}{/icon}</td>
<td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-editable" data-field="is_deductible" data-type="boolean">{if $row.is_deductible eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{$row.financial_account_type}{if $row.account_type_code} ({$row.account_type_code}){/if}</td>
<td>{$row.owned_by}</td>
<td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<div class="help">
{if $action eq 2}
{capture assign=crmURL}class="no-popup" href="{crmURL p="civicrm/group/search" q="reset=1&force=1&context=smog&gid=`$group.id`"}"{/capture}
- {ts 1=$crmURL}You can edit the Name and Description for this group here. Click <a %1>Contacts in this Group</a> to view, add or remove contacts in this group.{/ts}
+ {ts 1=$crmURL|smarty:nodefaults}You can edit the Name and Description for this group here. Click <a %1>Contacts in this Group</a> to view, add or remove contacts in this group.{/ts}
{else}
{ts}Enter a unique name and a description for your new group here. Then click 'Continue' to find contacts to add to your new group.{/ts}
{/if}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
{if $action neq 1}
<div class="action-link">
- <a {$crmURL}><i class="crm-i fa-users" aria-hidden="true"></i> {ts}Contacts in this Group{/ts}</a>
+ <a {$crmURL|smarty:nodefaults}><i class="crm-i fa-users" aria-hidden="true"></i> {ts}Contacts in this Group{/ts}</a>
{if $editSmartGroupURL}
<br />
- <a class="no-popup" href="{$editSmartGroupURL}"><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Smart Group Criteria{/ts}</a>
+ <a class="no-popup" href="{$editSmartGroupURL|smarty:nodefaults}"><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Smart Group Criteria{/ts}</a>
{/if}
</div>
{/if}
{$row.description|mb_truncate:80:"...":true}
</td>
<td>{$row.visibility}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
{if call_user_func(array('CRM_Campaign_BAO_Campaign','isCampaignEnable'))}
<td class="crm-mailing-campaign">{$row.campaign}</td>
{/if}
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{$row.body_text|escape}</td>
<td>{icon condition=$row.is_default}{ts}Default{/ts}{/icon} </td>
<td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crmf-is_admin crm-editable" data-type="boolean">{if $row.is_admin eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="nowrap crmf-weight">{$row.weight|smarty:nodefaults}</td>
<td class="crmf-is_reserved">{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{if !empty($row.action)}{$row.action|replace:'xx':$row.id}{/if}</td>
+ <td>{if !empty($row.action)}{$row.action|smarty:nodefaults|replace:'xx':$row.id}{/if}</td>
</tr>
{/foreach}
</table>
<td class="crmf-visibility crm-editable" data-type="select">{$row.visibility}</td>
<td class="nowrap crmf-weight">{$row.weight|smarty:nodefaults}</td>
<td class="crmf-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{$row.start_date|crmDate}</td>
<td>{if $row.end_date}{$row.end_date|crmDate}{else}({ts}ongoing{/ts}){/if}</td>
<td>{$row.status_id}</td>
- <td id={$row.id}>{$row.action|replace:'xx':$row.id}</td>
+ <td id={$row.id}>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</tbody>
</td>
<td>{if $row.html_type eq "Text / Numeric Quantity" }{$row.tax_amount|crmMoney}{/if}</td>
{/if}
- <td class="field-action">{$row.action|replace:'xx':$row.id}</td>
+ <td class="field-action">{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{$row.tax_amount|crmMoney}</td>
{/if}
<td id="row_{$row.id}_status" class="crm-price-option-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</tbody>
<td class="crmf-title crm-editable">{$row.title}</td>
<td class="crmf-extends">{$row.extends}</td>
<td class="crmf-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
</td>
<td class="crm-api-params">{if $row.api_params eq null}<em>{ts}no parameters{/ts}</em>{else}<pre>{$row.api_params}</pre>{/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td class="crm-editable crmf-is_required" data-type="boolean">{if $row.is_required eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td class="crm-editable crmf-is_view" data-type="boolean">{if $row.is_view eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
<td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/foreach}
</table>
<td>{$row.group_type}</td>
<td>{$row.id}</td>
<td>{$row.module}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/if}
{/foreach}
<td>{$row.group_type}</td>
<td>{$row.id}</td>
<td>{$row.module}</td>
- <td>{$row.action|replace:'xx':$row.id}</td>
+ <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
</tr>
{/if}
{/foreach}
'civicrm_uf_match' => [
0 => 'contact_id',
],
+ 'civicrm_user_job' => [
+ 0 => 'created_id',
+ ],
'civicrm_value_testgetcidref_1' => [
0 => 'entity_id',
],
if (CIVICRM_UF === 'WordPress') {
$cliRunners['wp'] = ['wp', 'wp eval \'civicrm_initialize();\'@PHP'];
}
- if (CIVICRM_UF === 'Drupal' || CIVICRM_UF === 'Backdrop') {
+ if (CIVICRM_UF === 'Drupal') {
+ $cliRunners['drush'] = ['drush', 'drush ev \'civicrm_initialize();\'@PHP'];
+ }
+ if (CIVICRM_UF === 'Backdrop' && version_compare(PHP_VERSION, '8', '<')) {
+ // At time of writing, "drush ev" doesn't work on our php80+backdrop environments
$cliRunners['drush'] = ['drush', 'drush ev \'civicrm_initialize();\'@PHP'];
}
// TODO: Drupal8 w/drush (doesn't use civicrm_initialize?)
--- /dev/null
+<?xml version="1.0" encoding="iso-8859-1" ?>
+
+<table>
+ <base>CRM/Core</base>
+ <class>UserJob</class>
+ <name>civicrm_user_job</name>
+ <comment>Tracking for user jobs (eg. imports).</comment>
+ <add>5.50</add>
+ <log>false</log>
+ <field>
+ <name>id</name>
+ <title>User Job ID</title>
+ <type>int unsigned</type>
+ <required>true</required>
+ <comment>Job ID</comment>
+ <html>
+ <type>Number</type>
+ </html>
+ <add>5.50</add>
+ </field>
+ <primaryKey>
+ <name>id</name>
+ <autoincrement>true</autoincrement>
+ </primaryKey>
+ <field>
+ <name>name</name>
+ <title>User job name</title>
+ <type>varchar</type>
+ <length>64</length>
+ <comment>Unique name for job.</comment>
+ <add>5.50</add>
+ </field>
+ <index>
+ <name>UI_name</name>
+ <fieldName>name</fieldName>
+ <unique>true</unique>
+ <add>5.50</add>
+ </index>
+ <field>
+ <name>created_id</name>
+ <type>int unsigned</type>
+ <title>Created By Contact ID</title>
+ <comment>FK to contact table.</comment>
+ <html>
+ <label>Created By</label>
+ </html>
+ <add>5.50</add>
+ </field>
+ <foreignKey>
+ <name>created_id</name>
+ <table>civicrm_contact</table>
+ <key>id</key>
+ <add>5.50</add>
+ <onDelete>SET NULL</onDelete>
+ </foreignKey>
+ <field>
+ <name>created_date</name>
+ <type>timestamp</type>
+ <default>CURRENT_TIMESTAMP</default>
+ <required>true</required>
+ <title>Import Job Created Date</title>
+ <readonly>true</readonly>
+ <comment>Date and time this job was created.</comment>
+ <add>5.50</add>
+ <html>
+ <type>Select Date</type>
+ <formatType>activityDateTime</formatType>
+ </html>
+ </field>
+ <field>
+ <name>start_date</name>
+ <type>timestamp</type>
+ <required>false</required>
+ <title>Import Job Started Date</title>
+ <comment>Date and time this import job started.</comment>
+ <add>5.50</add>
+ <html>
+ <type>Select Date</type>
+ <formatType>activityDateTime</formatType>
+ </html>
+ <readonly>true</readonly>
+ </field>
+ <field>
+ <name>end_date</name>
+ <type>timestamp</type>
+ <required>false</required>
+ <title>Job Ended Date</title>
+ <comment>Date and time this import job ended.</comment>
+ <add>5.50</add>
+ <html>
+ <type>Select Date</type>
+ <formatType>activityDateTime</formatType>
+ </html>
+ </field>
+ <field>
+ <name>expires_date</name>
+ <type>timestamp</type>
+ <required>false</required>
+ <title>Import Job Expires Date</title>
+ <comment>Date and time to clean up after this import job (temp table deletion date).</comment>
+ <add>5.50</add>
+ <html>
+ <type>Select Date</type>
+ <formatType>activityDateTime</formatType>
+ </html>
+ </field>
+ <field>
+ <name>status_id</name>
+ <title>User Job Status ID</title>
+ <type>int unsigned</type>
+ <required>true</required>
+ <html>
+ <label>Job Status</label>
+ </html>
+ <pseudoconstant>
+ <callback>CRM_Core_BAO_UserJob::getStatuses</callback>
+ </pseudoconstant>
+ <add>5.50</add>
+ </field>
+ <field>
+ <name>type_id</name>
+ <title>User Job Type ID</title>
+ <type>int unsigned</type>
+ <required>true</required>
+ <html>
+ <label>Job Type</label>
+ </html>
+ <pseudoconstant>
+ <callback>CRM_Core_BAO_UserJob::getTypes</callback>
+ </pseudoconstant>
+ <add>5.50</add>
+ </field>
+ <field>
+ <name>queue_id</name>
+ <title>Queue ID</title>
+ <type>int unsigned</type>
+ <comment>FK to Queue</comment>
+ <html>
+ <label>Queue</label>
+ </html>
+ </field>
+ <foreignKey>
+ <name>queue_id</name>
+ <table>civicrm_queue</table>
+ <key>id</key>
+ <onDelete>SET NULL</onDelete>
+ </foreignKey>
+ <field>
+ <name>metadata</name>
+ <type>text</type>
+ <title>Job metadata</title>
+ <comment>Data pertaining to job configuration</comment>
+ <serialize>JSON</serialize>
+ <add>5.50</add>
+ </field>
+</table>
<xi:include href="UFField.xml" parse="xml" />
<xi:include href="UFMatch.xml" parse="xml" />
<xi:include href="UFJoin.xml" parse="xml" />
+ <xi:include href="UserJob.xml" parse="xml" />
<xi:include href="Timezone.xml" parse="xml" />
<xi:include href="Worldregion.xml" parse="xml" />
<xi:include href="OpenID.xml" parse="xml" />