From 1149a00c8ac08dfd4aba47c7b34e1e22596038b9 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton <emcnaughton@wikimedia.org> Date: Thu, 2 Jun 2022 13:37:20 +1200 Subject: [PATCH] Handle error when creating related contact This addresses the e-notice identified here https://github.com/civicrm/civicrm-core/pull/23643#discussion_r887406505 I believe the bug report in that thread was a variant of the e-notice. Ie the import() function was failing to catch an exception & it was bubbling up to run() While there is no support currently for calling import() outside of run() - the intent is to replace run() with something more sane - which WILL be callable from the outside (likely via api). The right behaviour for import() is to catch all errors --- CRM/Contact/BAO/Contact.php | 2 +- CRM/Contact/Import/Parser/Contact.php | 70 ++----------------- .../CRM/Contact/Import/Parser/ContactTest.php | 10 ++- 3 files changed, 15 insertions(+), 67 deletions(-) diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index b808d6ed05..c0928f3e66 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -799,7 +799,7 @@ WHERE civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer'); * * @return CRM_Contact_BAO_Contact */ - public static function &retrieve(&$params, &$defaults, $microformat = FALSE) { + public static function &retrieve(&$params, &$defaults = [], $microformat = FALSE) { if (array_key_exists('contact_id', $params)) { $params['id'] = $params['contact_id']; } diff --git a/CRM/Contact/Import/Parser/Contact.php b/CRM/Contact/Import/Parser/Contact.php index e9c403f75c..903d7854d1 100644 --- a/CRM/Contact/Import/Parser/Contact.php +++ b/CRM/Contact/Import/Parser/Contact.php @@ -400,77 +400,21 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser { //format common data, CRM-4062 $this->formatCommonData($field, $formatting, $contactFields); - //fixed for CRM-4148 - if (!empty($formatting['id'])) { - $contact = [ - 'contact_id' => $formatting['id'], - ]; - $defaults = []; - $relatedNewContact = CRM_Contact_BAO_Contact::retrieve($contact, $defaults); - } - else { - $relatedNewContact = $this->createContact($formatting, $contactFields, $onDuplicate, NULL, FALSE); - } - - if (is_object($relatedNewContact) || ($relatedNewContact instanceof CRM_Contact_BAO_Contact)) { - $relatedNewContact = clone($relatedNewContact); - } - - $matchedIDs = []; - // To update/fill contact, get the matching contact Ids if duplicate contact found - // otherwise get contact Id from object of related contact - if (is_array($relatedNewContact)) { - $matchedIDs = $relatedNewContact; - } - else { - $matchedIDs[] = $relatedNewContact->id; - } - // update/fill related contact after getting matching Contact Ids, CRM-4424 - if (in_array($onDuplicate, [ - CRM_Import_Parser::DUPLICATE_UPDATE, - CRM_Import_Parser::DUPLICATE_FILL, - ])) { - //validation of related contact subtype for update mode - //CRM-5125 - $relatedCsType = NULL; - if (!empty($formatting['contact_sub_type'])) { - $relatedCsType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $matchedIDs[0], 'contact_sub_type'); + if (empty($formatting['id']) || $this->isUpdateExistingContacts()) { + try { + $relatedNewContact = $this->createContact($formatting, $contactFields, $onDuplicate, $formatting['id']); } - - if (!empty($relatedCsType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($matchedIDs[0], $relatedCsType) && $relatedCsType != CRM_Utils_Array::value('contact_sub_type', $formatting))) { - $this->setImportStatus((int) $values[count($values) - 1], 'invalid_no_match', 'Mismatched or Invalid contact subtype found for this related contact.'); + catch (CiviCRM_API3_Exception $e) { + $this->setImportStatus($rowNumber, 'ERROR', $e->getMessage()); return FALSE; } - else { - $this->createContact($formatting, $contactFields, $onDuplicate, $matchedIDs[0]); - } - } - static $relativeContact = []; - if (is_array($relatedNewContact)) { - if (count($matchedIDs) >= 1) { - $relContactId = $matchedIDs[0]; - //add relative contact to count during update & fill mode. - //logic to make count distinct by contact id. - if ($this->_newRelatedContacts || !empty($relativeContact)) { - $reContact = array_keys($relativeContact, $relContactId); - - if (empty($reContact)) { - $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; - } - } - else { - $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; - } - } - } - else { $relContactId = $relatedNewContact->id; - $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; + $this->_newRelatedContacts[$relContactId] = $relContactId; } if (1) { //fix for CRM-1993.Checks for duplicate related contacts - if (count($matchedIDs) >= 1) { + if (1) { //if more than one duplicate contact //found, create relationship with first contact // now create the relationship record diff --git a/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php b/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php index 32ae637ce3..17eebe4cad 100644 --- a/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php +++ b/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php @@ -2111,16 +2111,20 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase { /** * Test that import parser will not throw error if Related Contact is not found via passed in External ID. * + * If the organization is present it will create it - otherwise fail without error. + * + * @dataProvider getBooleanDataProvider + * * @throws \API_Exception * @throws \CRM_Core_Exception * @throws \CiviCRM_API3_Exception */ - public function testImportParserWithExternalIdForRelationship(): void { + public function testImportParserWithExternalIdForRelationship(bool $isOrganizationProvided): void { $contactImportValues = [ 'first_name' => 'Alok', 'last_name' => 'Patel', 'Employee of' => 'related external identifier', - 'organization_name' => 'Big shop', + 'organization_name' => $isOrganizationProvided ? 'Big shop' : '', ]; $mapper = [ @@ -2140,7 +2144,7 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase { $parser->init(); $parser->import(CRM_Import_Parser::DUPLICATE_UPDATE, $values); - $this->callAPISuccessGetCount('Contact', ['organization_name' => 'Big shop'], 2); + $this->callAPISuccessGetCount('Contact', ['organization_name' => 'Big shop'], $isOrganizationProvided ? 2 : 0); } } -- 2.25.1