Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 35 additions & 26 deletions CRM/Contact/BAO/Relationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static function create(&$params) {
// Check if this is a "simple" disable relationship. If it is don't check the relationshipType
$disableRelationship = !empty($params['id']) && array_key_exists('is_active', $params) && empty($params['is_active']);
if (!$disableRelationship && !CRM_Contact_BAO_Relationship::checkRelationshipType($params['contact_id_a'], $params['contact_id_b'], $params['relationship_type_id'])) {
throw new CRM_Core_Exception('Invalid Relationship');
throw new CRM_Core_Exception('Invalid Relationship', 'invalid_relationship');
}
$relationship = self::add($params);
if (!empty($params['contact_id_a'])) {
Expand Down Expand Up @@ -114,38 +114,47 @@ public static function create(&$params) {
*/
public static function createMultiple($params, $primaryContactLetter) {
$secondaryContactLetter = ($primaryContactLetter == 'a') ? 'b' : 'a';
$secondaryContactIDs = $params['contact_id_' . $secondaryContactLetter];
$valid = $invalid = $duplicate = $saved = 0;
$relationshipIDs = [];
foreach ($secondaryContactIDs as $secondaryContactID) {
try {
$params['contact_id_' . $secondaryContactLetter] = $secondaryContactID;
$relationship = civicrm_api3('relationship', 'create', $params);
$relationshipIDs[] = $relationship['id'];
$valid++;
$secondaryContactIDs = (array) ($params['contact_id_' . $secondaryContactLetter] ?? []);
unset($params['contact_id_' . $secondaryContactLetter]);

// Convert custom data to api4-style params
foreach ($params as $fieldName => $param) {
$customFieldName = CRM_Core_BAO_CustomField::getLongNameFromShortName($fieldName);
if ($customFieldName) {
$params[$customFieldName] = $param;
unset($params[$fieldName]);
}
catch (CRM_Core_Exception $e) {
switch ($e->getMessage()) {
case 'Duplicate Relationship':
$duplicate++;
break;

case 'Invalid Relationship':
$invalid++;
break;

default:
throw new CRM_Core_Exception('unknown relationship create error ' . $e->getMessage());
}
}

$invalid = $duplicate = 0;

$saveAction = \Civi\Api4\Relationship::save(FALSE)
->setDefaults($params);
foreach ($secondaryContactIDs as $secondaryContactID) {
$saveAction->addRecord(['contact_id_' . $secondaryContactLetter => $secondaryContactID]);
}
$saveResult = $saveAction->execute();

foreach ($saveResult->getErrors() as $error) {
switch ($error->getCode()) {
case 'duplicate':
$duplicate++;
break;

case 'invalid_relationship':
$invalid++;
break;

default:
throw new CRM_Core_Exception('unknown relationship create error ' . $error->getMessage());
}
}

return [
'valid' => $valid,
'valid' => $saveResult->count(),
'invalid' => $invalid,
'duplicate' => $duplicate,
'saved' => $saved,
'relationship_ids' => $relationshipIDs,
'relationship_ids' => $saveResult->column('id'),
];
}

Expand Down
23 changes: 15 additions & 8 deletions Civi/Api4/Action/Relationship/RelationshipSaveTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,34 @@

namespace Civi\Api4\Action\Relationship;

use Civi\Api4\Generic\Result;

/**
* @inheritDoc
*/
trait RelationshipSaveTrait {

/**
* @var \Civi\Api4\Generic\Result|null
*/
private $_result;

public function _run(Result $result) {
$this->_result = $result;
parent::_run($result);
}

/**
* @inheritDoc
*/
protected function write(array $items) {
$result = [];
foreach ($items as $item) {
foreach ($items as $index => $item) {
try {
$result[] = \CRM_Contact_BAO_Relationship::create($item);
$result[$index] = \CRM_Contact_BAO_Relationship::create($item);
}
catch (\CRM_Core_Exception $e) {
if ($e->getErrorCode() === 'duplicate') {
$result[] = $e->getErrorData();
}
else {
throw $e;
}
$this->_result->addError($e->getMessage(), code: $e->getErrorCode(), metadata: $e->getErrorData());
}
}
return $result;
Expand Down
81 changes: 81 additions & 0 deletions tests/phpunit/CRM/Contact/BAO/RelationshipTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,85 @@ public function testDisableInvalidRelationship(): void {
->execute();
}

/**
* Test CRM_Contact_BAO_Relationship::createMultiple handling of valid, duplicate, and invalid relationships.
*
* @throws \CRM_Core_Exception
*/
public function testCreateMultiple(): void {
$relTypeId = $this->relationshipTypeCreate([
'name_a_b' => 'Individual_To_Individual_A_B',
'name_b_a' => 'Individual_To_Individual_B_A',
'contact_type_a' => 'Individual',
'contact_type_b' => 'Individual',
]);

$individualA = $this->individualCreate(['display_name' => 'Primary Individual A']);
$individualBValid = $this->individualCreate(['display_name' => 'Secondary Individual Valid']);
$individualBDuplicate = $this->individualCreate(['display_name' => 'Secondary Individual Duplicate']);
$organizationBInvalid = $this->organizationCreate(['organization_name' => 'Secondary Org Invalid']);

// Create existing relationship for duplicate check
Relationship::create(FALSE)
->addValue('contact_id_a', $individualA)
->addValue('contact_id_b', $individualBDuplicate)
->addValue('relationship_type_id', $relTypeId)
->execute();

// Call createMultiple with primaryContactLetter = 'a'
$params = [
'contact_id_a' => $individualA,
'contact_id_b' => [$individualBValid, $individualBDuplicate, $organizationBInvalid],
'relationship_type_id' => $relTypeId,
];

$result = CRM_Contact_BAO_Relationship::createMultiple($params, 'a');

$this->assertEquals(1, $result['valid']);
$this->assertEquals(1, $result['duplicate']);
$this->assertEquals(1, $result['invalid']);
$this->assertCount(1, $result['relationship_ids']);

// Verify created relationship in DB
$createdRel = Relationship::get(FALSE)
->addWhere('id', '=', $result['relationship_ids'][0])
->execute()
->first();
$this->assertEquals($individualA, $createdRel['contact_id_a']);
$this->assertEquals($individualBValid, $createdRel['contact_id_b']);

// Call createMultiple with primaryContactLetter = 'b'
$individualB = $this->individualCreate(['display_name' => 'Primary Individual B']);
$individualAValid = $this->individualCreate(['display_name' => 'Secondary Individual A Valid']);
$individualADuplicate = $this->individualCreate(['display_name' => 'Secondary Individual A Duplicate']);
$organizationAInvalid = $this->organizationCreate(['organization_name' => 'Secondary Org A Invalid']);
$organizationBInvalid = $this->organizationCreate(['organization_name' => 'Secondary Org B Invalid']);

Relationship::create(FALSE)
->addValue('contact_id_a', $individualADuplicate)
->addValue('contact_id_b', $individualB)
->addValue('relationship_type_id', $relTypeId)
->execute();

$paramsB = [
'contact_id_a' => [$individualAValid, $individualADuplicate, $organizationAInvalid, $organizationBInvalid],
'contact_id_b' => $individualB,
'relationship_type_id' => $relTypeId,
];

$resultB = CRM_Contact_BAO_Relationship::createMultiple($paramsB, 'b');

$this->assertEquals(1, $resultB['valid']);
$this->assertEquals(1, $resultB['duplicate']);
$this->assertEquals(2, $resultB['invalid']);
$this->assertCount(1, $resultB['relationship_ids']);

$createdRelB = Relationship::get(FALSE)
->addWhere('id', '=', $resultB['relationship_ids'][0])
->execute()
->first();
$this->assertEquals($individualAValid, $createdRelB['contact_id_a']);
$this->assertEquals($individualB, $createdRelB['contact_id_b']);
}

}
25 changes: 14 additions & 11 deletions tests/phpunit/api/v3/RelationshipTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -333,29 +333,32 @@ public function testRelationshipCreateEditWithCustomData(): void {
$this->getCustomFieldName('link') => 'http://example.com',
];

$params = [
'contact_id_a' => $this->_cId_a,
'contact_id_b' => $this->_cId_b,
'relationship_type_id' => $this->relationshipTypeID,
$createParams = array_merge([
'relationship_type_id' => $this->relationshipTypeID . '_a_b',
'related_contact_id' => $this->_cId_b,
'start_date' => '2008-12-20',
'is_active' => 1,
];
$params = array_merge($params, $custom_params);
$result = $this->callAPISuccess('relationship', 'create', $params);
], $custom_params);

$relationParams = ['id' => $result['id']];
$this->assertDBState('CRM_Contact_DAO_Relationship', $result['id'], $relationParams);
$reln = new CRM_Contact_Form_Relationship();
$reln->_action = CRM_Core_Action::ADD;
$reln->_contactId = $this->_cId_a;
[, $relationshipIds] = $reln->submit($createParams);
$relationshipId = $relationshipIds[0];

$getParams = ['id' => $relationshipId];
$check = $this->callAPISuccess('relationship', 'get', $getParams);
$this->assertEquals('Hello! this is custom data for relationship', $check['values'][$check['id']][$this->getCustomFieldName('text')]);

//Test Edit of custom field from the form.
$getParams = ['id' => $result['id']];
$updateParams = array_merge($getParams, [
$this->getCustomFieldName('text') => 'Edited Text Value',
'relationship_type_id' => $this->relationshipTypeID . '_b_a',
'related_contact_id' => $this->_cId_a,
]);
$reln = new CRM_Contact_Form_Relationship();
$reln->_action = CRM_Core_Action::UPDATE;
$reln->_relationshipId = $result['id'];
$reln->_relationshipId = $relationshipId;
$reln->submit($updateParams);

$check = $this->callAPISuccess('relationship', 'get', $getParams);
Expand Down