diff --git a/CRM/Contact/Import/Form/MapField.php b/CRM/Contact/Import/Form/MapField.php
index 39e4ca1dce8d..e79fd196b20d 100644
--- a/CRM/Contact/Import/Form/MapField.php
+++ b/CRM/Contact/Import/Form/MapField.php
@@ -101,17 +101,8 @@ public function preProcess() {
// retrieve and highlight required custom fields
$formattedFieldNames = $this->formatCustomFieldName($this->_mapperFields);
- $this->assign('highlightedFields', $this->getHighlightedFields());
$this->_formattedFieldNames[$contactType] = $this->_mapperFields = array_merge($this->_mapperFields, $formattedFieldNames);
-
- $columnNames = $this->getColumnHeaders();
-
- $this->_columnCount = $this->getNumberOfColumns();
- $this->_columnNames = $columnNames;
- $this->assign('columnNames', $this->getColumnHeaders());
- $this->assign('columnCount', $this->_columnCount);
- $this->_dataValues = array_values($this->getDataRows([], 2));
- $this->assign('dataValues', $this->_dataValues);
+ $this->assignMapFieldVariables();
}
/**
@@ -512,7 +503,7 @@ private function isSkipDuplicates(): bool {
*
* @throws \CRM_Core_Exception
*/
- private function getHighlightedFields(): array {
+ protected function getHighlightedFields(): array {
$entityFields = [
'Individual' => ['first_name', 'last_name'],
'Organization' => ['organization_name'],
diff --git a/CRM/Contact/Import/Form/Preview.php b/CRM/Contact/Import/Form/Preview.php
index 3bf15b4ea251..37ad7552ec20 100644
--- a/CRM/Contact/Import/Form/Preview.php
+++ b/CRM/Contact/Import/Form/Preview.php
@@ -15,6 +15,9 @@
* @copyright CiviCRM LLC https://civicrm.org/licensing
*/
+use Civi\Api4\Group;
+use Civi\Api4\Tag;
+
/**
* This class previews the uploaded file and returns summary statistics.
*/
@@ -34,38 +37,8 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
* @throws \CRM_Core_Exception
*/
public function preProcess() {
- $columnNames = $this->getColumnHeaders();
+ parent::preProcess();
$this->_disableUSPS = $this->getSubmittedValue('disableUSPS');
-
- //assign column names
- $this->assign('columnNames', $columnNames);
-
- //get the mapping name displayed if the mappingId is set
- $mappingId = $this->get('loadMappingId');
- if ($mappingId) {
- $mapDAO = new CRM_Core_DAO_Mapping();
- $mapDAO->id = $mappingId;
- $mapDAO->find(TRUE);
- }
- $this->assign('savedMappingName', $mappingId ? $mapDAO->name : NULL);
-
- $this->assign('rowDisplayCount', 2);
-
- $groups = CRM_Core_PseudoConstant::nestedGroup();
- $this->set('groups', $groups);
-
- $tag = CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', array('onlyActive' => FALSE));
- if ($tag) {
- $this->set('tag', $tag);
- }
-
- $this->assign('downloadErrorRecordsUrl', $this->getDownloadURL(CRM_Import_Parser::ERROR));
- $this->assign('invalidRowCount', $this->getRowCount(CRM_Import_Parser::ERROR));
- $this->assign('validRowCount', $this->getRowCount(CRM_Import_Parser::VALID));
- $this->assign('totalRowCount', $this->getRowCount([]));
- $this->assign('mapper', $this->getMappedFieldLabels());
- $this->assign('dataValues', $this->getDataRows([], 2));
-
$this->setStatusUrl();
}
@@ -84,24 +57,25 @@ public function buildQuickForm() {
);
}
- $groups = $this->get('groups');
+ $groups = CRM_Core_PseudoConstant::nestedGroup();;
if (!empty($groups)) {
- $this->addElement('select', 'groups', ts('Add imported records to existing group(s)'), $groups, array(
+ $this->addElement('select', 'groups', ts('Add imported records to existing group(s)'), $groups, [
'multiple' => "multiple",
'class' => 'crm-select2',
- ));
+ ]);
}
//display new tag
$this->addElement('text', 'newTagName', ts('Tag'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'name'));
$this->addElement('text', 'newTagDesc', ts('Description'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'description'));
- $tag = $this->get('tag');
+ $tag = CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]);
if (!empty($tag)) {
- foreach ($tag as $tagID => $tagName) {
- $this->addElement('checkbox', "tag[$tagID]", NULL, $tagName);
- }
+ $this->addElement('select', 'tag', ts(' Tag imported records'), $tag, [
+ 'multiple' => 'multiple',
+ 'class' => 'crm-select2',
+ ]);
}
$this->addFormRule(array('CRM_Contact_Import_Form_Preview', 'formRule'), $this);
@@ -163,37 +137,71 @@ public static function formRule($fields, $files, $self) {
/**
* Process the mapped fields and map it into the uploaded file.
*
- * @throws \API_Exception
+ * @throws \API_Exception|\CRM_Core_Exception
*/
- public function postProcess() {
-
- $importJobParams = array(
- 'doGeocodeAddress' => $this->getSubmittedValue('doGeocodeAddress'),
- 'invalidRowCount' => $this->getRowCount(CRM_Import_Parser::ERROR),
- 'onDuplicate' => $this->getSubmittedValue('onDuplicate'),
- 'dedupe' => $this->getSubmittedValue('dedupe_rule_id'),
- 'newGroupName' => $this->controller->exportValue($this->_name, 'newGroupName'),
- 'newGroupDesc' => $this->controller->exportValue($this->_name, 'newGroupDesc'),
- 'newGroupType' => $this->controller->exportValue($this->_name, 'newGroupType'),
- 'groups' => $this->controller->exportValue($this->_name, 'groups'),
- 'allGroups' => $this->get('groups'),
- 'newTagName' => $this->controller->exportValue($this->_name, 'newTagName'),
- 'newTagDesc' => $this->controller->exportValue($this->_name, 'newTagDesc'),
- 'tag' => $this->controller->exportValue($this->_name, 'tag'),
- 'allTags' => $this->get('tag'),
- 'mapper' => $this->controller->exportValue('MapField', 'mapper'),
- 'mapFields' => $this->getAvailableFields(),
- 'contactType' => $this->getContactType(),
- 'contactSubType' => $this->getSubmittedValue('contactSubType'),
- 'primaryKeyName' => '_id',
- 'statusFieldName' => '_status',
- 'statusID' => $this->get('statusID'),
- 'totalRowCount' => $this->getRowCount([]),
- 'userJobID' => $this->getUserJobID(),
- );
+ public function postProcess(): void {
+ $groupsToAddTo = (array) $this->getSubmittedValue('groups');
+ $summaryInfo = ['groups' => [], 'tags' => []];
+ foreach ($groupsToAddTo as $groupID) {
+ // This is a convenience for now - really url & name should be determined at
+ // presentation stage - ie the summary screen. The only info we are really
+ // preserving is which groups were created vs already existed.
+ $summaryInfo['groups'][$groupID] = [
+ 'url' => CRM_Utils_System::url('civicrm/group/search', 'reset=1&force=1&context=smog&gid=' . $groupID),
+ 'name' => Group::get(FALSE)->addWhere('id', '=', $groupID)->addSelect('name')->execute()->first()['name'],
+ 'new' => FALSE,
+ 'added' => 0,
+ 'notAdded' => 0,
+ ];
+ }
- $importJob = new CRM_Contact_Import_ImportJob();
- $importJob->setJobParams($importJobParams);
+ if ($this->getSubmittedValue('newGroupName')) {
+ /* Create a new group */
+ $groupsToAddTo[] = $groupID = Group::create(FALSE)->setValues([
+ 'title' => $this->getSubmittedValue('newGroupName'),
+ 'description' => $this->getSubmittedValue('newGroupDesc'),
+ 'group_type' => $this->getSubmittedValue('newGroupType') ?? [],
+ 'is_active' => TRUE,
+ ])->execute()->first()['id'];
+ $summaryInfo['groups'][$groupID] = [
+ 'url' => CRM_Utils_System::url('civicrm/group/search', 'reset=1&force=1&context=smog&gid=' . $groupID),
+ 'name' => $this->getSubmittedValue('newGroupName'),
+ 'new' => TRUE,
+ 'added' => 0,
+ 'notAdded' => 0,
+ ];
+ }
+ $tagsToAdd = (array) $this->getSubmittedValue('tag');
+ foreach ($tagsToAdd as $tagID) {
+ // This is a convenience for now - really url & name should be determined at
+ // presentation stage - ie the summary screen. The only info we are really
+ // preserving is which tags were created vs already existed.
+ $summaryInfo['tags'][$tagID] = [
+ 'url' => CRM_Utils_System::url('civicrm/contact/search', 'reset=1&force=1&context=smog&id=' . $tagID),
+ 'name' => Tag::get(FALSE)->addWhere('id', '=', $tagID)->addSelect('name')->execute()->first()['name'],
+ 'new' => TRUE,
+ 'added' => 0,
+ 'notAdded' => 0,
+ ];
+ }
+ if ($this->getSubmittedValue('newTagName')) {
+ $tagsToAdd[] = $tagID = Tag::create(FALSE)->setValues([
+ 'name' => $this->getSubmittedValue('newTagName'),
+ 'description' => $this->getSubmittedValue('newTagDesc'),
+ 'is_selectable' => TRUE,
+ 'used_for' => 'civicrm_contact',
+ ])->execute()->first()['id'];
+ $summaryInfo['tags'][$tagID] = [
+ 'url' => CRM_Utils_System::url('civicrm/contact/search', 'reset=1&force=1&context=smog&id=' . $tagID),
+ 'name' => $this->getSubmittedValue('newTagName'),
+ 'new' => FALSE,
+ 'added' => 0,
+ 'notAdded' => 0,
+ ];
+ }
+ // Store the actions to take on each row & the data to present at the end to the userJob.
+ $this->updateUserJobMetadata('post_actions', ['group' => $groupsToAddTo, 'tag' => $tagsToAdd]);
+ $this->updateUserJobMetadata('summary_info', $summaryInfo);
// If ACL applies to the current user, update cache before running the import.
if (!CRM_Core_Permission::check('view all contacts')) {
@@ -205,16 +213,20 @@ public function postProcess() {
CRM_Utils_Address_USPS::disable($this->_disableUSPS);
// run the import
- $importJob->runImport($this);
+
+ $this->_parser = $this->getParser();
+ $this->_parser->run(
+ [],
+ CRM_Import_Parser::MODE_IMPORT,
+ $this->get('statusID')
+ );
// Clear all caches, forcing any searches to recheck the ACLs or group membership as the import
// may have changed it.
CRM_Contact_BAO_Contact_Utils::clearContactCaches(TRUE);
- // add all the necessary variables to the form
- $importJob->setFormVariables($this);
-
// check if there is any error occurred
+ // @todo - it's really unclear that this error code should still exist...
$errorStack = CRM_Core_Error::singleton();
$errors = $errorStack->getErrors();
$errorMessage = [];
@@ -235,10 +247,6 @@ public function postProcess() {
$this->set('errorFile', $errorFile);
}
-
- //hack to clean db
- //if job complete drop table.
- $importJob->isComplete();
}
/**
diff --git a/CRM/Contact/Import/Form/Summary.php b/CRM/Contact/Import/Form/Summary.php
index d4a4655af7bd..33d02af4c63d 100644
--- a/CRM/Contact/Import/Form/Summary.php
+++ b/CRM/Contact/Import/Form/Summary.php
@@ -27,7 +27,8 @@ class CRM_Contact_Import_Form_Summary extends CRM_Import_Form_Summary {
* @throws \CRM_Core_Exception
*/
public function preProcess() {
- // set the error message path to display
+ // @todo - totally unclear that this errorFile could ever be set / render.
+ // Probably it can go.
$this->assign('errorFile', $this->get('errorFile'));
$onDuplicate = $this->getSubmittedValue('onDuplicate');
$this->assign('dupeError', FALSE);
@@ -44,8 +45,8 @@ public function preProcess() {
$this->assign('dupeError', TRUE);
}
- $this->assign('groupAdditions', $this->get('groupAdditions'));
- $this->assign('tagAdditions', $this->get('tagAdditions'));
+ $this->assign('groupAdditions', $this->getUserJob()['metadata']['summary_info']['groups']);
+ $this->assign('tagAdditions', $this->getUserJob()['metadata']['summary_info']['tags']);
$this->assign('totalRowCount', $this->getRowCount());
$this->assign('validRowCount', $this->getRowCount(CRM_Import_Parser::VALID) + $this->getRowCount(CRM_Import_Parser::UNPARSED_ADDRESS_WARNING));
$this->assign('invalidRowCount', $this->getRowCount(CRM_Import_Parser::ERROR));
diff --git a/CRM/Contact/Import/ImportJob.php b/CRM/Contact/Import/ImportJob.php
index 035f6abe4d45..a61ec1899022 100644
--- a/CRM/Contact/Import/ImportJob.php
+++ b/CRM/Contact/Import/ImportJob.php
@@ -23,14 +23,10 @@ class CRM_Contact_Import_ImportJob {
protected $_onDuplicate;
protected $_dedupe;
protected $_newGroupName;
- protected $_newGroupDesc;
- protected $_newGroupType;
protected $_groups;
protected $_allGroups;
protected $_newTagName;
- protected $_newTagDesc;
protected $_tag;
- protected $_allTags;
protected $_mapper;
protected $_mapperKeys = [];
@@ -72,44 +68,6 @@ public function runImport(&$form, $timeout = 55) {
$this->_mapperKeys[$key] = $mapper[$key][0] ?? NULL;
}
- $this->_parser = new CRM_Contact_Import_Parser_Contact(
- $this->_mapperKeys
- );
- $this->_parser->setUserJobID($this->_userJobID);
- $this->_parser->run(
- [],
- CRM_Import_Parser::MODE_IMPORT,
- $this->_statusID
- );
-
- $contactIds = $this->_parser->getImportedContacts();
-
- //get the related contactIds. CRM-2926
- $relatedContactIds = $this->_parser->getRelatedImportedContacts();
- if ($relatedContactIds) {
- $contactIds = array_merge($contactIds, $relatedContactIds);
- }
-
- if ($this->_newGroupName || count($this->_groups)) {
- $groupAdditions = $this->_addImportedContactsToNewGroup($contactIds,
- $this->_newGroupName,
- $this->_newGroupDesc,
- $this->_newGroupType
- );
- if ($form) {
- $form->set('groupAdditions', $groupAdditions);
- }
- }
-
- if ($this->_newTagName || !empty($this->_tag)) {
- $tagAdditions = $this->_tagImportedContactsWithNewTag($contactIds,
- $this->_newTagName,
- $this->_newTagDesc
- );
- if ($form) {
- $form->set('tagAdditions', $tagAdditions);
- }
- }
}
/**
@@ -119,118 +77,4 @@ public function setFormVariables($form) {
$this->_parser->set($form, CRM_Import_Parser::MODE_IMPORT);
}
- /**
- * Add imported contacts.
- *
- * @param array $contactIds
- * @param string $newGroupName
- * @param string $newGroupDesc
- * @param string $newGroupType
- *
- * @return array|bool
- */
- private function _addImportedContactsToNewGroup(
- $contactIds,
- $newGroupName, $newGroupDesc, $newGroupType
- ) {
-
- $newGroupId = NULL;
-
- if ($newGroupName) {
- /* Create a new group */
- $newGroupType = $newGroupType ?? [];
- $gParams = array(
- 'title' => $newGroupName,
- 'description' => $newGroupDesc,
- 'group_type' => $newGroupType,
- 'is_active' => TRUE,
- );
- $group = CRM_Contact_BAO_Group::create($gParams);
- $this->_groups[] = $newGroupId = $group->id;
- }
-
- if (is_array($this->_groups)) {
- $groupAdditions = [];
- foreach ($this->_groups as $groupId) {
- $addCount = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId);
- $totalCount = $addCount[1];
- if ($groupId == $newGroupId) {
- $name = $newGroupName;
- $new = TRUE;
- }
- else {
- $name = $this->_allGroups[$groupId];
- $new = FALSE;
- }
- $groupAdditions[] = array(
- 'url' => CRM_Utils_System::url('civicrm/group/search',
- 'reset=1&force=1&context=smog&gid=' . $groupId
- ),
- 'name' => $name,
- 'added' => $totalCount,
- 'notAdded' => $addCount[2],
- 'new' => $new,
- );
- }
- return $groupAdditions;
- }
- return FALSE;
- }
-
- /**
- * @param $contactIds
- * @param string $newTagName
- * @param $newTagDesc
- *
- * @return array|bool
- * @throws \CRM_Core_Exception
- */
- private function _tagImportedContactsWithNewTag(
- $contactIds,
- $newTagName, $newTagDesc
- ) {
-
- $newTagId = NULL;
- if ($newTagName) {
- /* Create a new Tag */
-
- $tagParams = array(
- 'name' => $newTagName,
- 'description' => $newTagDesc,
- 'is_selectable' => TRUE,
- 'used_for' => 'civicrm_contact',
- );
- $addedTag = CRM_Core_BAO_Tag::add($tagParams);
- $this->_tag[$addedTag->id] = 1;
- }
- //add Tag to Import
-
- if (is_array($this->_tag)) {
- $tagAdditions = [];
- foreach ($this->_tag as $tagId => $val) {
- $addTagCount = CRM_Core_BAO_EntityTag::addEntitiesToTag($contactIds, $tagId, 'civicrm_contact', FALSE);
- $totalTagCount = $addTagCount[1];
- if (isset($addedTag) && $tagId == $addedTag->id) {
- $tagName = $newTagName;
- $new = TRUE;
- }
- else {
- $tagName = $this->_allTags[$tagId];
- $new = FALSE;
- }
- $tagAdditions[] = array(
- 'url' => CRM_Utils_System::url('civicrm/contact/search',
- 'reset=1&force=1&context=smog&id=' . $tagId
- ),
- 'name' => $tagName,
- 'added' => $totalTagCount,
- 'notAdded' => $addTagCount[2],
- 'new' => $new,
- );
- }
- return $tagAdditions;
- }
- return FALSE;
- }
-
}
diff --git a/CRM/Contact/Import/MetadataTrait.php b/CRM/Contact/Import/MetadataTrait.php
index fc8d57048427..368df0e11a93 100644
--- a/CRM/Contact/Import/MetadataTrait.php
+++ b/CRM/Contact/Import/MetadataTrait.php
@@ -81,7 +81,7 @@ protected function getRelationships(): array {
*
* @return array
*/
- public function getHeaderPatterns() {
+ public function getHeaderPatterns(): array {
return CRM_Utils_Array::collect('headerPattern', $this->getContactImportMetadata());
}
@@ -90,7 +90,7 @@ public function getHeaderPatterns() {
*
* @return array
*/
- public function getDataPatterns() {
+ public function getDataPatterns(): array {
return CRM_Utils_Array::collect('dataPattern', $this->getContactImportMetadata());
}
diff --git a/CRM/Contact/Import/Parser/Contact.php b/CRM/Contact/Import/Parser/Contact.php
index 5092ac1da60a..198dba14ae1b 100644
--- a/CRM/Contact/Import/Parser/Contact.php
+++ b/CRM/Contact/Import/Parser/Contact.php
@@ -209,6 +209,7 @@ public function getAllFields() {
*/
public function import($onDuplicate, &$values) {
$rowNumber = (int) $values[array_key_last($values)];
+
$this->_unparsedStreetAddressContacts = [];
if (!$this->getSubmittedValue('doGeocodeAddress')) {
// CRM-5854, reset the geocode method to null to prevent geocoding
@@ -251,11 +252,7 @@ public function import($onDuplicate, &$values) {
//fixed CRM-4148
//now we create new contact in update/fill mode also.
$newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $params['id'] ?? NULL, TRUE, $this->_dedupeRuleGroupID);
-
- if (!is_array($newContact)) {
- $contactID = $newContact->id;
- $this->_newContacts[] = $contactID;
- }
+ $this->createdContacts[$newContact->id] = $contactID = $newContact->id;
if ($contactID) {
// call import hook
@@ -296,18 +293,17 @@ public function import($onDuplicate, &$values) {
if (empty($formatting['id']) || $this->isUpdateExistingContacts()) {
try {
$relatedNewContact = $this->createContact($formatting, $contactFields, $onDuplicate, $formatting['id']);
+ $relContactId = $relatedNewContact->id;
+ $this->createdContacts[$relContactId] = $relContactId;
}
catch (CiviCRM_API3_Exception $e) {
$this->setImportStatus($rowNumber, 'ERROR', $e->getMessage());
return FALSE;
}
- $relContactId = $relatedNewContact->id;
- $this->_newRelatedContacts[$relContactId] = $relContactId;
}
$this->createRelationship($key, $relContactId, $primaryContactId);
}
}
-
$this->setImportStatus($rowNumber, $this->getStatus(CRM_Import_Parser::VALID), $this->getSuccessMessage(), $contactID);
return CRM_Import_Parser::VALID;
}
@@ -569,16 +565,7 @@ private function formatCommonData($params, &$formatted) {
* @return array
*/
public function getImportedContacts() {
- return $this->_newContacts;
- }
-
- /**
- * Get the array of successfully imported related contact id's
- *
- * @return array
- */
- public function &getRelatedImportedContacts() {
- return $this->_newRelatedContacts;
+ return $this->createdContacts;
}
/**
@@ -1256,6 +1243,8 @@ public function run(
// here to make sure it is instantiated.
$this->getContactType();
$this->getContactSubType();
+ // Reset user job in case to null in case it was loaded prior to the job being complete.
+ $this->userJob = NULL;
$this->init();
@@ -1290,6 +1279,7 @@ public function run(
$prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
}
}
+ $this->doPostImportActions();
}
/**
@@ -1367,24 +1357,6 @@ public static function exportCSV($fileName, $header, $data) {
fclose($fd);
}
- /**
- * Update the status of the import row to reflect the processing outcome.
- *
- * @param int $id
- * @param string $status
- * @param string $message
- * @param int|null $entityID
- * Optional created entity ID
- * @param array $relatedEntityIDs
- * Optional array e.g ['related_contact' => 4]
- *
- * @throws \API_Exception
- * @throws \CRM_Core_Exception
- */
- public function setImportStatus(int $id, string $status, string $message, ?int $entityID = NULL, array $relatedEntityIDs = []): void {
- $this->getDataSourceObject()->updateStatus($id, $status, $message, $entityID, $relatedEntityIDs);
- }
-
/**
* Format contact parameters.
*
diff --git a/CRM/Import/Form/MapField.php b/CRM/Import/Form/MapField.php
index 9c10336654f4..1f9187c35ec4 100644
--- a/CRM/Import/Form/MapField.php
+++ b/CRM/Import/Form/MapField.php
@@ -66,6 +66,14 @@ public function getTitle() {
return ts('Match Fields');
}
+ /**
+ * Shared preProcess code.
+ */
+ public function preProcess() {
+ $this->assignMapFieldVariables();
+ parent::preProcess();
+ }
+
/**
* Attempt to match header labels with our mapper fields.
*
diff --git a/CRM/Import/Form/Preview.php b/CRM/Import/Form/Preview.php
index 3ba704f33987..cce75402e928 100644
--- a/CRM/Import/Form/Preview.php
+++ b/CRM/Import/Form/Preview.php
@@ -36,8 +36,7 @@ public function getTitle() {
* Assign common values to the template.
*/
public function preProcess() {
- $this->assign('skipColumnHeader', $this->getSubmittedValue('skipColumnHeader'));
- $this->assign('rowDisplayCount', $this->getSubmittedValue('skipColumnHeader') ? 3 : 2);
+ $this->assignPreviewVariables();
}
/**
@@ -91,4 +90,31 @@ public function setStatusUrl() {
$this->assign('statusUrl', $statusUrl);
}
+ /**
+ * Assign smarty variables for the preview screen.
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
+ */
+ protected function assignPreviewVariables(): void {
+ $this->assign('downloadErrorRecordsUrl', $this->getDownloadURL(CRM_Import_Parser::ERROR));
+ $this->assign('invalidRowCount', $this->getRowCount(CRM_Import_Parser::ERROR));
+ $this->assign('validRowCount', $this->getRowCount(CRM_Import_Parser::VALID));
+ $this->assign('totalRowCount', $this->getRowCount([]));
+ $this->assign('mapper', $this->getMappedFieldLabels());
+ $this->assign('dataValues', $this->getDataRows([], 2));
+ $this->assign('columnNames', $this->getColumnHeaders());
+ //get the mapping name displayed if the mappingId is set
+ $mappingId = $this->get('loadMappingId');
+ if ($mappingId) {
+ $mapDAO = new CRM_Core_DAO_Mapping();
+ $mapDAO->id = $mappingId;
+ $mapDAO->find(TRUE);
+ }
+ $this->assign('savedMappingName', $mappingId ? $mapDAO->name : NULL);
+ $this->assign('skipColumnHeader', $this->getSubmittedValue('skipColumnHeader'));
+ // rowDisplayCount is deprecated - it used to be used with {section} but we have nearly gotten rid of it.
+ $this->assign('rowDisplayCount', $this->getSubmittedValue('skipColumnHeader') ? 3 : 2);
+ }
+
}
diff --git a/CRM/Import/Forms.php b/CRM/Import/Forms.php
index 6c61172567b3..c3f364600213 100644
--- a/CRM/Import/Forms.php
+++ b/CRM/Import/Forms.php
@@ -586,4 +586,53 @@ protected function getMappedFieldLabels(): array {
return $mapper;
}
+ /**
+ * Assign variables required for the MapField form.
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
+ */
+ protected function assignMapFieldVariables(): void {
+ $this->addExpectedSmartyVariable('highlightedRelFields');
+ $this->_columnCount = $this->getNumberOfColumns();
+ $this->_columnNames = $this->getColumnHeaders();
+ $this->_dataValues = array_values($this->getDataRows([], 2));
+ $this->assign('columnNames', $this->getColumnHeaders());
+ $this->assign('highlightedFields', $this->getHighlightedFields());
+ $this->assign('columnCount', $this->_columnCount);
+ $this->assign('dataValues', $this->_dataValues);
+ }
+
+ /**
+ * Get the fields to be highlighted in the UI.
+ *
+ * The highlighted fields are those used to match
+ * to an existing entity.
+ *
+ * @return array
+ *
+ * @throws \CRM_Core_Exception
+ */
+ protected function getHighlightedFields(): array {
+ return [];
+ }
+
+ /**
+ * Get the data patterns to pattern match the incoming data.
+ *
+ * @return array
+ */
+ public function getDataPatterns(): array {
+ return $this->getParser()->getDataPatterns();
+ }
+
+ /**
+ * Get the data patterns to pattern match the incoming data.
+ *
+ * @return array
+ */
+ public function getHeaderPatterns(): array {
+ return $this->getParser()->getHeaderPatterns();
+ }
+
}
diff --git a/CRM/Import/Parser.php b/CRM/Import/Parser.php
index d25e5e1a55b1..8a12340f48fb 100644
--- a/CRM/Import/Parser.php
+++ b/CRM/Import/Parser.php
@@ -53,6 +53,13 @@ abstract class CRM_Import_Parser {
*/
protected $userJobID;
+ /**
+ * The user job in use.
+ *
+ * @var array
+ */
+ protected $userJob;
+
/**
* Potentially ambiguous options.
*
@@ -76,6 +83,13 @@ public function getUserJobID(): ?int {
return $this->userJobID;
}
+ /**
+ * Ids of contacts created this iteration.
+ *
+ * @var array
+ */
+ protected $createdContacts = [];
+
/**
* Set user job ID.
*
@@ -105,10 +119,13 @@ public function setUserJobID(int $userJobID): self {
* @throws \API_Exception
*/
protected function getUserJob(): array {
- return UserJob::get()
- ->addWhere('id', '=', $this->getUserJobID())
- ->execute()
- ->first();
+ if (empty($this->userJob)) {
+ $this->userJob = UserJob::get()
+ ->addWhere('id', '=', $this->getUserJobID())
+ ->execute()
+ ->first();
+ }
+ return $this->userJob;
}
/**
@@ -510,7 +527,7 @@ public function getSelectTypes() {
/**
* @return array
*/
- public function getHeaderPatterns() {
+ public function getHeaderPatterns(): array {
$values = [];
foreach ($this->_fields as $name => $field) {
if (isset($field->_headerPattern)) {
@@ -523,7 +540,7 @@ public function getHeaderPatterns() {
/**
* @return array
*/
- public function getDataPatterns() {
+ public function getDataPatterns():array {
$values = [];
foreach ($this->_fields as $name => $field) {
$values[$name] = $field->_dataPattern;
@@ -606,6 +623,76 @@ protected function validateRequiredContactFields(string $contactType, array $par
$this->validateRequiredFields($requiredFields, $params, $prefixString);
}
+ protected function doPostImportActions() {
+ $userJob = $this->getUserJob();
+ $summaryInfo = $userJob['metadata']['summary_info'];
+ $actions = $userJob['metadata']['post_actions'];
+ if (!empty($actions['group'])) {
+ $groupAdditions = $this->addImportedContactsToNewGroup($this->createdContacts, $actions['group']);
+ foreach ($actions['group'] as $groupID) {
+ $summaryInfo['groups'][$groupID]['added'] += $groupAdditions[$groupID]['added'];
+ $summaryInfo['groups'][$groupID]['notAdded'] += $groupAdditions[$groupID]['notAdded'];
+ }
+ }
+ if (!empty($actions['tag'])) {
+ $tagAdditions = $this->tagImportedContactsWithNewTag($this->createdContacts, $actions['tag']);
+ foreach ($actions['tag'] as $tagID) {
+ $summaryInfo['tags'][$tagID]['added'] += $tagAdditions[$tagID]['added'];
+ $summaryInfo['tags'][$tagID]['notAdded'] += $tagAdditions[$tagID]['notAdded'];
+ }
+ }
+
+ $this->userJob['metadata']['summary_info'] = $summaryInfo;
+ UserJob::update(FALSE)->addWhere('id', '=', $userJob['id'])->setValues(['metadata' => $this->userJob['metadata']])->execute();
+ }
+
+ /**
+ * Add imported contacts to groups.
+ *
+ * @param array $contactIDs
+ * @param array $groups
+ *
+ * @return array
+ */
+ private function addImportedContactsToNewGroup(array $contactIDs, array $groups): array {
+ $groupAdditions = [];
+ foreach ($groups as $groupID) {
+ // @todo - this function has been in use historically but it does not seem
+ // to add much efficiency of get + create api calls
+ // and it doesn't give enough control over cache flushing for smaller batches.
+ // Note that the import updates a lot of enities & checking & updating the group
+ // shouldn't add much performance wise. However, cache flushing will
+ $addCount = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIDs, $groupID);
+ $groupAdditions[$groupID] = [
+ 'added' => (int) $addCount[1],
+ 'notAdded' => (int) $addCount[2],
+ ];
+ }
+ return $groupAdditions;
+ }
+
+ /**
+ * Tag imported contacts.
+ *
+ * @param array $contactIDs
+ * @param array $tags
+ *
+ * @return array
+ */
+ private function tagImportedContactsWithNewTag(array $contactIDs, array $tags) {
+ $tagAdditions = [];
+ foreach ($tags as $tagID) {
+ // @todo - this function has been in use historically but it does not seem
+ // to add much efficiency of get + create api calls
+ // and it doesn't give enough control over cache flushing for smaller batches.
+ // Note that the import updates a lot of enities & checking & updating the group
+ // shouldn't add much performance wise. However, cache flushing will
+ $outcome = CRM_Core_BAO_EntityTag::addEntitiesToTag($contactIDs, $tagID, 'civicrm_contact', FALSE);
+ $tagAdditions[$tagID] = ['added' => $outcome[1], 'notAdded' => $outcome[2]];
+ }
+ return $tagAdditions;
+ }
+
/**
* Determines the file extension based on error code.
*
@@ -1521,6 +1608,29 @@ protected function isAmbiguous(string $fieldName, $importedValue): bool {
return !empty($this->ambiguousOptions[$fieldName][mb_strtolower($importedValue)]);
}
+ /**
+ * Get the civicrm_mapping_field appropriate layout for the mapper input.
+ *
+ * For simple parsers (not contribution or contact) the input looks like
+ * ['first_name', 'custom_32']
+ * and it is converted to
+ *
+ * ['name' => 'first_name', 'mapping_id' => 1, 'column_number' => 5],
+ *
+ * @param array $fieldMapping
+ * @param int $mappingID
+ * @param int $columnNumber
+ *
+ * @return array
+ */
+ public function getMappingFieldFromMapperInput(array $fieldMapping, int $mappingID, int $columnNumber): array {
+ return [
+ 'name' => $fieldMapping[0],
+ 'mapping_id' => $mappingID,
+ 'column_number' => $columnNumber,
+ ];
+ }
+
/**
* Get the field mappings for the import.
*
@@ -1616,4 +1726,20 @@ protected function getSubtypes($contactType) {
return $subTypes;
}
+ /**
+ * Update the status of the import row to reflect the processing outcome.
+ *
+ * @param int $id
+ * @param string $status
+ * @param string $message
+ * @param int|null $entityID
+ * Optional created entity ID
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
+ */
+ protected function setImportStatus(int $id, string $status, string $message, ?int $entityID = NULL): void {
+ $this->getDataSourceObject()->updateStatus($id, $status, $message, $entityID);
+ }
+
}
diff --git a/templates/CRM/Contact/Import/Form/MapTable.tpl b/templates/CRM/Contact/Import/Form/MapTable.tpl
index e0fbce6125fb..b13969c0fddd 100644
--- a/templates/CRM/Contact/Import/Form/MapTable.tpl
+++ b/templates/CRM/Contact/Import/Form/MapTable.tpl
@@ -7,111 +7,26 @@
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*}
-
+ });
+ }
+ });
+
+ {/literal}
+{/if}
diff --git a/templates/CRM/Contact/Import/Form/Preview.tpl b/templates/CRM/Contact/Import/Form/Preview.tpl
index 503d561a5f7a..77b28e9b6f95 100644
--- a/templates/CRM/Contact/Import/Form/Preview.tpl
+++ b/templates/CRM/Contact/Import/Form/Preview.tpl
@@ -128,9 +128,7 @@
diff --git a/templates/CRM/Import/Form/MapTableCommon.tpl b/templates/CRM/Import/Form/MapTableCommon.tpl
new file mode 100644
index 000000000000..83fa1fcc8e48
--- /dev/null
+++ b/templates/CRM/Import/Form/MapTableCommon.tpl
@@ -0,0 +1,92 @@
+
diff --git a/templates/CRM/common/highLightImport.tpl b/templates/CRM/common/highLightImport.tpl
index bd9156c941c2..6279ff532b90 100644
--- a/templates/CRM/common/highLightImport.tpl
+++ b/templates/CRM/common/highLightImport.tpl
@@ -14,7 +14,7 @@ CRM.$(function($) {
$.each(highlightedFields, function() {
$('select[id^="mapper"][id$="_0"] option[value='+ this + ']').append(' *').css({"color":"#FF0000"});
});
- {/literal}{if $relationship}{literal}
+ {/literal}{if $highlightedRelFields}{literal}
var highlightedRelFields = {/literal}{$highlightedRelFields|@json_encode}{literal};
function highlight() {
var select, fields = highlightedRelFields[$(this).val()];