return CRM_Import_Parser::ERROR;
}
- // sleep(3);
+
+ if (empty($this->_unparsedStreetAddressContacts)) {
+ $this->setImportStatus((int) ($values[count($values) - 1]), 'IMPORTED', '', $contactID);
+ return CRM_Import_Parser::VALID;
+ }
+
+ // @todo - record unparsed address as 'imported' but the presence of a message is meaningful?
return $this->processMessage($values, $statusFieldName, CRM_Import_Parser::VALID);
}
* @param array $mapper
* @param int $mode
* @param int $statusID
- * @param int $totalRowCount
*
* @return mixed
* @throws \API_Exception|\CRM_Core_Exception
public function run(
$mapper = [],
$mode = self::MODE_PREVIEW,
- $statusID = NULL,
- $totalRowCount = NULL
+ $statusID = NULL
) {
// TODO: Make the timeout actually work
$this->_rowCount = 0;
$this->_totalCount = 0;
- $this->_tableName = $tableName = $this->getUserJob()['metadata']['DataSource']['table_name'];
$this->_primaryKeyName = '_id';
$this->_statusFieldName = '_status';
$this->progressImport($statusID);
$startTimestamp = $currTimestamp = $prevTimestamp = time();
}
- // get the contents of the temp. import table
- $query = "SELECT * FROM $tableName";
+ $dataSource = $this->getDataSourceObject();
+ $totalRowCount = $dataSource->getRowCount(['new']);
if ($mode == self::MODE_IMPORT) {
- $query .= " WHERE _status = 'NEW'";
+ $dataSource->setStatuses(['new']);
}
if ($this->_maxLinesToProcess > 0) {
// Note this would only be the case in MapForm mode, where it is set to 100
// which is the number of columns a row might have.
// However, the mapField class may no longer use activeFieldsCount for contact
// to be continued....
- $query .= ' LIMIT ' . $this->_maxLinesToProcess;
+ $dataSource->setLimit($this->_maxLinesToProcess);
}
- $result = CRM_Core_DAO::executeQuery($query);
-
- while ($result->fetch()) {
- $values = array_values($result->toArray());
+ while ($row = $dataSource->getRow()) {
+ $values = array_values($row);
$this->_rowCount++;
- /* trim whitespace around the values */
- foreach ($values as $k => $v) {
- $values[$k] = trim($v, " \t\r\n");
- }
-
$this->_totalCount++;
if ($mode == self::MODE_MAPFIELD) {
}
/**
- * 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.
+ * 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): 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'],
- ]);
- }
+ public function setImportStatus(int $id, string $status, string $message, ?int $entityID = NULL, array $relatedEntityIDs = []): void {
+ $this->getDataSourceObject()->updateStatus($id, $status, $message, $entityID, $relatedEntityIDs);
}
/**
return $params;
}
- /**
- * Is the job complete.
- *
- * This function transitionally accesses the table from the userJob
- * directly - but the function should be moved to the dataSource class.
- *
- * @throws \API_Exception
- */
- public function isComplete() {
- $tableName = $this->getUserJob()['metadata']['DataSource']['table_name'];
- return (bool) CRM_Core_DAO::singleValueQuery("SELECT count(*) FROM $tableName WHERE _status = 'NEW' LIMIT 1");
- }
-
/**
* Validate the import values.
*
protected function addTrackingFieldsToTable(string $tableName): void {
CRM_Core_DAO::executeQuery("
ALTER TABLE $tableName
+ ADD COLUMN _entity_id INT,
+ ADD COLUMN _related_entity_ids JSON,
ADD COLUMN _status VARCHAR(32) DEFAULT 'NEW' NOT NULL,
- ADD COLUMN _statusMsg TEXT,
+ ADD COLUMN _status_message TEXT,
ADD COLUMN _id INT PRIMARY KEY NOT NULL AUTO_INCREMENT"
);
}
+ /**
+ * Has the import job completed.
+ *
+ * @return bool
+ * True if no rows remain to be imported.
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
+ */
+ public function isCompleted(): bool {
+ return (bool) $this->getRowCount(['new']);
+ }
+
+ /**
+ * 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 updateStatus(int $id, string $status, string $message, ? int $entityID = NULL, array $relatedEntityIDs = []): void {
+ $sql = 'UPDATE ' . $this->getTableName() . ' SET _status = %1, _status_message = %2 ';
+ $params = [1 => [$status, 'String'], 2 => [$message, 'String']];
+ if ($entityID) {
+ $sql .= ', _entity_id = %3';
+ $params[3] = [$entityID, 'Integer'];
+ }
+ if ($relatedEntityIDs) {
+ $sql .= ', _related_entities = %4';
+ $params[4] = [json_encode($relatedEntityIDs), 'String'];
+ }
+ CRM_Core_DAO::executeQuery($sql . ' WHERE _id = ' . $id, $params);
+ }
+
/**
*
* @throws \API_Exception
CRM_Import_Parser::DUPLICATE => ['duplicate'],
CRM_Import_Parser::NO_MATCH => ['invalid_no_match'],
CRM_Import_Parser::UNPARSED_ADDRESS_WARNING => ['warning_unparsed_address'],
+ 'new' => ['new'],
];
}
$message = array_pop($record);
// Also pop off the status - but we are not going to use this at this stage.
array_pop($record);
+ // Related entities
+ array_pop($record);
+ // Entity_id
+ array_pop($record);
array_unshift($record, $message);
array_unshift($record, $rowNumber);
return $record;
->first();
}
+ /**
+ * Get the relevant datasource object.
+ *
+ * @return \CRM_Import_DataSource|null
+ *
+ * @throws \API_Exception
+ */
+ protected function getDataSourceObject(): ?CRM_Import_DataSource {
+ $className = $this->getSubmittedValue('dataSource');
+ if ($className) {
+ /* @var CRM_Import_DataSource $dataSource */
+ return new $className($this->getUserJobID());
+ }
+ return NULL;
+ }
+
/**
* Get the submitted value, as stored on the user job.
*
return $this->getUserJob()['metadata']['submitted_values'][$fieldName];
}
+ /**
+ * Has the import completed.
+ *
+ * @return bool
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
+ */
+ public function isComplete() :bool {
+ return $this->getDataSourceObject()->isCompleted();
+ }
+
/**
* Get configured contact type.
*
--- /dev/null
+,eileen,eileen-laptop,11.05.2022 11:24,file:///home/eileen/.config/libreoffice/4;
\ No newline at end of file
--- /dev/null
+Player First Name,Player Last name,Mother – email
+Susie,Jones,mum@example.org
--- /dev/null
+Player First Name,Player Last name,Mother – phone
+Blake,Jackson,911
$processor = new CRM_Import_ImportProcessor();
$processor->setMappingFields($mapping);
- $processor->setUserJobID($this->getUserJobID([
- 'mapper' => $mapperInput,
- ]));
+ $userJobID = $this->getUserJobID(['mapper' => $mapperInput]);
+ $processor->setUserJobID($userJobID);
$importer = $processor->getImporterObject();
$contactValues = [
foreach ($fields as $index => $field) {
$mapper[] = [$field, $mapperLocType[$index] ?? NULL, $field === 'phone' ? 1 : NULL];
}
+ $userJobID = $this->getUserJobID(['mapper' => $mapper]);
$parser = new CRM_Contact_Import_Parser_Contact($fields, $mapperLocType);
- $parser->setUserJobID($this->getUserJobID([
- 'mapper' => $mapper,
- ]));
+ $parser->setUserJobID($userJobID);
$parser->_dedupeRuleGroupID = $ruleGroupId;
$parser->_onDuplicate = $onDuplicateAction;
$parser->init();
* @throws \Civi\API\Exception\UnauthorizedException
*/
protected function getUserJobID($submittedValues = []) {
- return UserJob::create()->setValues([
+ $userJobID = UserJob::create()->setValues([
'metadata' => [
'submitted_values' => array_merge([
'contactType' => CRM_Import_Parser::CONTACT_INDIVIDUAL,
'contactSubType' => '',
'doGeocodeAddress' => 0,
+ 'dataSource' => 'CRM_Import_DataSource_SQL',
+ 'sqlQuery' => 'SELECT first_name FROM civicrm_contact',
], $submittedValues),
],
'status_id:name' => 'draft',
'type_id:name' => 'contact_import',
])->execute()->first()['id'];
+ if ($submittedValues['dataSource'] ?? NULL === 'CRM_Import_DataSource') {
+ $dataSource = new CRM_Import_DataSource_CSV($userJobID);
+ }
+ else {
+ $dataSource = new CRM_Import_DataSource_SQL($userJobID);
+ }
+ $dataSource->initialize();
+ return $userJobID;
}
/**
'skipColumnHeader' => TRUE,
'fieldSeparator' => ',',
'mapper' => $mapper,
+ 'dataSource' => 'CRM_Import_DataSource_CSV',
]);
$dataSource = new CRM_Import_DataSource_CSV($userJobID);
- $dataSource->initialize();
$parser = new CRM_Contact_Import_Parser_Contact();
$parser->setUserJobID($userJobID);
$parser->init();
* edge case. Note if it has more than one column then the blank line gets
* skipped because of some checking for column-count matches in the import,
* and so you don't hit the current fail.
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
*/
public function testBlankLineAtEnd(): void {
$form = $this->submitDatasourceForm('blankLineAtEnd.csv');
* @param string $csvFileName
*
* @return \CRM_Contact_Import_Form_DataSource
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
*/
protected function submitDatasourceForm(string $csvFileName): CRM_Contact_Import_Form_DataSource {
$_GET['dataSource'] = 'CRM_Import_DataSource_CSV';
],
'skipColumnHeader' => TRUE,
'contactType' => CRM_Import_Parser::CONTACT_INDIVIDUAL,
+ 'dataSource' => 'CRM_Import_DataSource_CSV',
]);
$form->buildForm();
$form->postProcess();