*/
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.
*
* The initializer code, called before the processing.
*/
public function init() {
- $activityContact = CRM_Activity_BAO_ActivityContact::import();
- $activityTarget['target_contact_id'] = $activityContact['contact_id'];
- $fields = array_merge(CRM_Activity_BAO_Activity::importableFields(),
- $activityTarget
- );
-
- $fields = array_merge($fields, [
- 'source_contact_id' => [
- 'title' => ts('Source Contact'),
- 'headerPattern' => '/Source.Contact?/i',
- ],
- 'activity_label' => [
- 'title' => ts('Activity Type Label'),
- 'headerPattern' => '/(activity.)?type label?/i',
- ],
- ]);
-
- foreach ($fields as $name => $field) {
+ $this->setFieldMetadata();
+
+ foreach ($this->importableFieldsMetadata as $name => $field) {
$field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT);
$field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//');
$field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//');
*
* @param array $values
* The array of values belonging to this line.
- *
- * @return int
- * CRM_Import_Parser::VALID for success or
- * CRM_Import_Parser::ERROR for error.
- *
- * @throws \CRM_Core_Exception
*/
- public function import(&$values) {
+ public function import($values) {
+ $rowNumber = (int) ($values[array_key_last($values)]);
// First make sure this is a valid line
try {
- $this->validateValues($values);
-
- $params = $this->getApiReadyParams($values);
- // For date-Formats.
- $session = CRM_Core_Session::singleton();
- $dateType = $session->get('dateTypes');
-
- $customFields = CRM_Core_BAO_CustomField::getFields('Activity');
-
- foreach ($params as $key => $val) {
- if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
- if (!empty($customFields[$customFieldID]) && $customFields[$customFieldID]['data_type'] == 'Date') {
- $this->formatCustomDate($params, $params, $dateType, $key);
- }
- elseif (!empty($customFields[$customFieldID]) && $customFields[$customFieldID]['data_type'] == 'Boolean') {
- $params[$key] = CRM_Utils_String::strtoboolstr($val);
- }
- }
- elseif ($key === 'activity_date_time') {
- $params[$key] = CRM_Utils_Date::formatDate($val, $dateType);
- }
- elseif ($key === 'activity_subject') {
- $params['subject'] = $val;
- }
- }
+ $params = $this->getMappedRow($values);
if (empty($params['external_identifier']) && empty($params['target_contact_id'])) {
if (!empty($matchedIDs)) {
if (count($matchedIDs) > 1) {
- array_unshift($values, 'Multiple matching contact records detected for this row. The activity was not imported');
- return CRM_Import_Parser::ERROR;
+ throw new CRM_Core_Exception('Multiple matching contact records detected for this row. The activity was not imported');
}
$cid = $matchedIDs[0];
$params['target_contact_id'] = $cid;
$params['version'] = 3;
$newActivity = civicrm_api('activity', 'create', $params);
if (!empty($newActivity['is_error'])) {
- array_unshift($values, $newActivity['error_message']);
- return CRM_Import_Parser::ERROR;
+ throw new CRM_Core_Exception($newActivity['error_message']);
}
$this->_newActivity[] = $newActivity['id'];
- return CRM_Import_Parser::VALID;
+ $this->setImportStatus($rowNumber, 'IMPORTED', '', $newActivity['id']);
+ return;
}
// Using new Dedupe rule.
}
}
- array_unshift($values, 'No matching Contact found for (' . $disp . ')');
- return CRM_Import_Parser::ERROR;
+ throw new CRM_Core_Exception('No matching Contact found for (' . $disp . ')');
}
if (!empty($params['external_identifier'])) {
$targetContactId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
if (!empty($params['target_contact_id']) &&
$params['target_contact_id'] != $targetContactId
) {
- array_unshift($values, 'Mismatch of External ID:' . $params['external_identifier'] . ' and Contact Id:' . $params['target_contact_id']);
- return CRM_Import_Parser::ERROR;
+ throw new CRM_Core_Exception('Mismatch of External ID:' . $params['external_identifier'] . ' and Contact Id:' . $params['target_contact_id']);
}
if ($targetContactId) {
$params['target_contact_id'] = $targetContactId;
}
else {
- array_unshift($values, 'No Matching Contact for External ID:' . $params['external_identifier']);
- return CRM_Import_Parser::ERROR;
+ throw new CRM_Core_Exception('No Matching Contact for External ID:' . $params['external_identifier']);
}
}
$params['version'] = 3;
$newActivity = civicrm_api('activity', 'create', $params);
if (!empty($newActivity['is_error'])) {
- array_unshift($values, $newActivity['error_message']);
- return CRM_Import_Parser::ERROR;
+ throw new CRM_Core_Exception($newActivity['error_message']);
}
}
catch (CRM_Core_Exception $e) {
- return $this->addError($values, [$e->getMessage()]);
+ $this->setImportStatus($rowNumber, 'ERROR', $e->getMessage());
+ return;
}
$this->_newActivity[] = $newActivity['id'];
- return CRM_Import_Parser::VALID;
+ $this->setImportStatus($rowNumber, 'IMPORTED', '', $newActivity['id']);
+ }
+
+ /**
+ * Get the row from the csv mapped to our parameters.
+ *
+ * @param array $values
+ *
+ * @return array
+ * @throws \API_Exception
+ */
+ public function getMappedRow(array $values): array {
+ $params = [];
+ foreach ($this->getFieldMappings() as $i => $mappedField) {
+ if ($mappedField['name'] === 'do_not_import') {
+ continue;
+ }
+ if ($mappedField['name']) {
+ $fieldName = $this->getFieldMetadata($mappedField['name'])['name'];
+ if (in_array($mappedField['name'], ['target_contact_id', 'source_contact_id'])) {
+ $fieldName = $mappedField['name'];
+ }
+ $params[$fieldName] = $this->getTransformedFieldValue($mappedField['name'], $values[$i]);
+ }
+ }
+ return $params;
}
/**
return $row[$this->getFieldIndex($fieldName)] ?? NULL;
}
+ /**
+ * @return array
+ */
+ protected function getRequiredFields(): array {
+ return [['activity_type_id' => ts('Activity Type'), 'activity_date_time' => ts('Activity Date')]];
+ }
+
/**
* Get the index for the given field.
*
}
}
- /**
- * @param array $values
- *
- * @throws \CRM_Core_Exception
- */
- public function validateValues(array $values): void {
- // Check required fields if this is not an update.
- if (!$this->getFieldValue($values, 'activity_id')) {
- if (!$this->getFieldValue($values, 'activity_label')
- && !$this->getFieldValue($values, 'activity_type_id')) {
- throw new CRM_Core_Exception(ts('Missing required fields: Activity type label or Activity type ID'));
- }
- if (!$this->getFieldValue($values, 'activity_date_time')) {
- throw new CRM_Core_Exception(ts('Missing required fields'));
- }
- }
-
- $this->validateActivityTypeIDAndLabel($values);
- if ($this->getFieldValue($values, 'activity_date_time')
- && !$this->isValidDate($this->getFieldValue($values, 'activity_date_time'))) {
- throw new CRM_Core_Exception(ts('Invalid Activity Date'));
- }
-
- if ($this->getFieldValue($values, 'activity_engagement_level')
- && !CRM_Utils_Rule::positiveInteger($this->getFieldValue($values, 'activity_engagement_level'))) {
- throw new CRM_Core_Exception(ts('Activity Engagement Index'));
- }
-
- $targetContactID = $this->getFieldValue($values, 'target_contact_id');
- if ($targetContactID && !$this->isValidContactID($targetContactID)) {
- throw new CRM_Core_Exception("Invalid Contact ID: There is no contact record with contact_id = " . CRM_Utils_Type::escape($targetContactID, 'String'));
- }
- $this->validateCustomFields($values);
- }
-
/**
* Get array of parameters formatted for the api from the submitted values.
*
* @param int $onDuplicate
* @param int $statusID
* @param int $totalRowCount
- *
- * @return mixed
- * @throws Exception
*/
public function run(
array $fileName,
$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 = 0;
$this->_invalidRowCount = $this->_validCount = 0;
$this->_totalCount = 0;
$this->_errors = [];
$this->_warnings = [];
-
- $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2);
-
if ($mode == self::MODE_MAPFIELD) {
$this->_rows = [];
}
$startTimestamp = $currTimestamp = $prevTimestamp = time();
}
- while (!feof($fd)) {
+ $dataSource = $this->getDataSourceObject();
+ $dataSource->setStatuses(['new']);
+ while ($row = $dataSource->getRow()) {
$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.
- foreach ($values as $k => $v) {
- $values[$k] = trim($v, " \t\r\n");
- }
-
- if (CRM_Utils_System::isNull($values)) {
- continue;
- }
-
+ $values = array_values($row);
$this->_totalCount++;
if ($mode == self::MODE_MAPFIELD) {
$returnCode = $this->summary($values);
}
elseif ($mode == self::MODE_IMPORT) {
- $returnCode = $this->import($values);
+ $this->import($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::ERROR) {
- $this->_invalidRowCount++;
- $recordNumber = $this->_lineCount;
- if ($this->_haveColumnHeader) {
- $recordNumber--;
- }
- array_unshift($values, $recordNumber);
- $this->_errors[] = $values;
- }
-
- // 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);
- }
}
}
*
* @param CRM_Core_Session $store
*/
- public function set($store) {
- $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);
-
- if ($this->_invalidRowCount) {
- $store->set('errorsFileName', $this->_errorFileName);
- }
-
- if (isset($this->_rows) && !empty($this->_rows)) {
- $store->set('dataValues', $this->_rows);
- }
- }
+ public function set($store) {}
/**
* Export data to a CSV file.
fclose($fd);
}
+ /**
+ * Ensure metadata is loaded.
+ */
+ protected function setFieldMetadata(): void {
+ if (empty($this->importableFieldsMetadata)) {
+ $activityContact = CRM_Activity_BAO_ActivityContact::import();
+ $activityTarget['target_contact_id'] = $activityContact['contact_id'];
+ $fields = array_merge(CRM_Activity_BAO_Activity::importableFields(),
+ $activityTarget
+ );
+
+ $fields = array_merge($fields, [
+ 'source_contact_id' => [
+ 'title' => ts('Source Contact'),
+ 'headerPattern' => '/Source.Contact?/i',
+ ],
+ ]);
+ $this->importableFieldsMetadata = $fields;
+ }
+ }
+
}