*
* @param array $params
* @param int|null $extIDMatch
- * @param int|null $dedupeRuleID
+ * @param int|string $dedupeRuleID
*
* @return int|null
* IDs of a possible.
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
- protected function getPossibleContactMatch(array $params, ?int $extIDMatch, ?int $dedupeRuleID): ?int {
- $checkParams = ['check_permissions' => FALSE, 'match' => $params, 'dedupe_rule_id' => $dedupeRuleID];
- $possibleMatches = civicrm_api3('Contact', 'duplicatecheck', $checkParams);
+ protected function getPossibleContactMatch(array $params, ?int $extIDMatch, $dedupeRuleID): ?int {
+ $possibleMatches = $this->getPossibleMatchesByDedupeRule($params, $dedupeRuleID);
if (!$extIDMatch) {
- if (count($possibleMatches['values']) === 1) {
- return array_key_last($possibleMatches['values']);
+ if (count($possibleMatches) === 1) {
+ return array_key_last($possibleMatches);
}
- if (count($possibleMatches['values']) > 1) {
- throw new CRM_Core_Exception(ts('Record duplicates multiple contacts: ') . implode(',', array_keys($possibleMatches['values'])), CRM_Import_Parser::ERROR);
-
+ if (count($possibleMatches) > 1) {
+ throw new CRM_Core_Exception(ts('Record duplicates multiple contacts: ') . implode(',', array_keys($possibleMatches)), CRM_Import_Parser::ERROR);
}
return NULL;
}
- if ($possibleMatches['count']) {
- if (array_key_exists($extIDMatch, $possibleMatches['values'])) {
+ if (count($possibleMatches) > 0) {
+ if (array_key_exists($extIDMatch, $possibleMatches)) {
return $extIDMatch;
}
throw new CRM_Core_Exception(ts('Matching this contact based on the de-dupe rule would cause an external ID conflict'), CRM_Import_Parser::ERROR);
use Civi\Api4\Campaign;
use Civi\Api4\Contact;
use Civi\Api4\CustomField;
+use Civi\Api4\DedupeRuleGroup;
use Civi\Api4\Event;
use Civi\Api4\UserJob;
use Civi\UserJob\UserJobInterface;
return ['is_error' => 0];
}
+ /**
+ * Get the default dedupe rule name for the contact type.
+ *
+ * @param string $contactType
+ *
+ * @return string
+ */
+ protected function getDefaultRuleForContactType(string $contactType): string {
+ return $contactType . '.Unsupervised';
+ }
+
+ /**
+ * Get the dedupe rule name.
+ *
+ * @param int $id
+ *
+ * @return string
+ *
+ * @throws \CRM_Core_Exception
+ */
+ protected function getDedupeRuleName(int $id): string {
+ return DedupeRuleGroup::get(FALSE)
+ ->addWhere('id', '=', $id)
+ ->addSelect('name')
+ ->execute()->first()['name'];
+ }
+
/**
* This function adds the contact variable in $values to the
* parameter list $params. For most cases, $values should have length 1. If
* @throws \API_Exception
*/
protected function getFieldEntity(string $fieldName) {
- if ($fieldName === 'do_not_import') {
+ if ($fieldName === 'do_not_import' || $fieldName === '') {
return '';
}
if (in_array($fieldName, ['email_greeting_id', 'postal_greeting_id', 'addressee_id'], TRUE)) {
return (int) $foundContact['id'];
}
+ /**
+ * Get contacts that match the input parameters, using a dedupe rule.
+ *
+ * @param array $params
+ * @param int|null $dedupeRuleID
+ *
+ * @return array
+ *
+ * @throws \CRM_Core_Exception
+ */
+ protected function getPossibleMatchesByDedupeRule(array $params, $dedupeRuleID = NULL): array {
+ foreach (['email', 'address', 'phone', 'im'] as $locationEntity) {
+ if (array_key_exists($locationEntity, $params)) {
+ // Prefer primary
+ if (array_key_exists('Primary', $params[$locationEntity])) {
+ $locationParams = $params[$locationEntity]['Primary'];
+ }
+ else {
+ // Chose the first one - at least they can manipulate the order.
+ $locationParams = reset($params[$locationEntity]);
+ }
+ foreach ($locationParams as $key => $locationParam) {
+ // Even though we might not be using 'primary' we 'pretend' here
+ // since the apiv4 code expects that...
+ $params[$locationEntity . '_primary' . '.' . $key] = $locationParam;
+ }
+ unset($params[$locationEntity]);
+ }
+ }
+ foreach ($params as $key => $value) {
+ if (strpos($key, 'custom_') === 0) {
+ $params[$this->getApi4Name($key)] = $value;
+ unset($params[$key]);
+ }
+ }
+ $dedupeRule = $dedupeRuleID ? $this->getDedupeRuleName($dedupeRuleID) : $this->getDefaultRuleForContactType($params['contact_type']);
+ $possibleMatches = Contact::getDuplicates(FALSE)
+ ->setValues($params)
+ ->setDedupeRule($dedupeRule)
+ ->execute();
+
+ $matchIDs = [];
+ foreach ($possibleMatches as $possibleMatch) {
+ $matchIDs[(int) $possibleMatch['id']] = (int) $possibleMatch['id'];
+ }
+ return $matchIDs;
+ }
+
+ /**
+ * Get the Api4 name of a custom field.
+ *
+ * @param string $key
+ *
+ * @throws \CRM_Core_Exception
+ */
+ protected function getApi4Name(string $key): string {
+ return Contact::getFields(FALSE)
+ ->addWhere('custom_field_id', '=', $this->getFieldMetadata($key)['custom_field_id'])
+ ->addSelect('name')
+ ->execute()->first()['name'];
+ }
+
}
/**
* Test that import parser will add contact with employee of relationship.
*
- * @throws \API_Exception
* @throws \CRM_Core_Exception
- * @throws \CiviCRM_API3_Exception
*/
public function testImportParserWithEmployeeOfRelationship(): void {
$this->organizationCreate([
$this->callAPISuccessGetCount('IM', ['contact_id' => $id], 1);
}
-
/**
* Test whether importing a contact using email match will match a non-primary.
*
$parser->import($values);
$dataSource = new CRM_Import_DataSource_SQL($userJobID);
$row = $dataSource->getRow();
- $this->assertEquals($expected, $row['_status']);
+ $this->assertEquals($expected, $row['_status'], print_r($row, TRUE));
}
}