From 89e45979567e990d55222dea60e737252c086c60 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Wed, 21 Mar 2018 16:29:54 +0000 Subject: [PATCH] CRM-21849: Support fetching options for relationship type --- CRM/Contact/BAO/Relationship.php | 69 ++++++++++++++ .../CRM/Contact/BAO/RelationshipTest.php | 93 +++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php index 29a2f7adeb..bc6ea7ae57 100644 --- a/CRM/Contact/BAO/Relationship.php +++ b/CRM/Contact/BAO/Relationship.php @@ -2149,4 +2149,73 @@ AND cc.sort_name LIKE '%$name%'"; return $relationshipsDT; } + /** + * @inheritdoc + */ + public static function buildOptions($fieldName, $context = NULL, $props = array()) { + if ($fieldName === 'relationship_type_id') { + return self::buildRelationshipTypeOptions($props); + } + + return parent::buildOptions($fieldName, $context, $props); + } + + /** + * Builds a list of options available for relationship types + * + * @param array $params + * - contact_type: Limits by contact type on the "A" side + * - relationship_id: Used to find the value for contact type for "B" side. + * If contact_a matches provided contact_id then type of contact_b will + * be used. Otherwise uses type of contact_a. Must be used with contact_id + * - contact_id: Limits by contact types of this contact on the "A" side + * - is_form: Returns array with keys indexed for use in a quickform + * - relationship_direction: For relationship types with duplicate names + * on both sides, defines which option should be returned, a_b or b_a + * + * @return array + */ + public static function buildRelationshipTypeOptions($params = array()) { + $contactId = CRM_Utils_Array::value('contact_id', $params); + $direction = CRM_Utils_Array::value('relationship_direction', $params, 'a_b'); + $relationshipId = CRM_Utils_Array::value('relationship_id', $params); + $contactType = CRM_Utils_Array::value('contact_type', $params); + $isForm = CRM_Utils_Array::value('is_form', $params); + $showAll = FALSE; + + // getContactRelationshipType will return an empty set if these are not set + if (!$contactId && !$relationshipId && !$contactType) { + $showAll = TRUE; + } + + $labels = self::getContactRelationshipType( + $contactId, + $direction, + $relationshipId, + $contactType, + $showAll, + 'label' + ); + + if ($isForm) { + return $labels; + } + + $names = self::getContactRelationshipType( + $contactId, + $direction, + $relationshipId, + $contactType, + $showAll, + 'name' + ); + + // ensure $names contains only entries in $labels + $names = array_intersect_key($names, $labels); + + $nameToLabels = array_combine($names, $labels); + + return $nameToLabels; + } + } diff --git a/tests/phpunit/CRM/Contact/BAO/RelationshipTest.php b/tests/phpunit/CRM/Contact/BAO/RelationshipTest.php index 4bb2d254ed..9311d222e6 100644 --- a/tests/phpunit/CRM/Contact/BAO/RelationshipTest.php +++ b/tests/phpunit/CRM/Contact/BAO/RelationshipTest.php @@ -48,9 +48,102 @@ class CRM_Contact_BAO_RelationshipTest extends CiviUnitTestCase { * This method is called after a test is executed. */ protected function tearDown() { + $this->quickCleanup([ + 'civicrm_relationship_type', + 'civicrm_relationship', + 'civicrm_contact' + ]); + parent::tearDown(); } + public function testRelationshipTypeOptionsWillReturnSpecifiedType() { + $orgToOrgType = 'A_B_relationship'; + $orgToOrgReverseType = 'B_A_relationship'; + civicrm_api3('RelationshipType', 'create', [ + 'name_a_b' => $orgToOrgType, + 'name_b_a' => $orgToOrgReverseType, + 'contact_type_a' => 'Organization', + 'contact_type_b' => 'Organization', + ]); + + $result = CRM_Contact_BAO_Relationship::buildRelationshipTypeOptions( + ['contact_type' => 'Organization'] + ); + $this->assertContains($orgToOrgType, $result); + $this->assertContains($orgToOrgReverseType, $result); + + $result = CRM_Contact_BAO_Relationship::buildRelationshipTypeOptions( + ['contact_type' => 'Individual'] + ); + + $this->assertNotContains($orgToOrgType, $result); + $this->assertNotContains($orgToOrgReverseType, $result); + } + + public function testContactIdAndRelationshipIdWillBeUsedInFilter() { + $individual = civicrm_api3('Contact', 'create', [ + 'display_name' => 'Individual A', + 'contact_type' => 'Individual', + ]); + $organization = civicrm_api3('Contact', 'create', [ + 'organization_name' => 'Organization B', + 'contact_type' => 'Organization', + ]); + + $personToOrgType = 'A_B_relationship'; + $orgToPersonType = 'B_A_relationship'; + + $orgToPersonTypeId = civicrm_api3('RelationshipType', 'create', [ + 'name_a_b' => $personToOrgType, + 'name_b_a' => $orgToPersonType, + 'contact_type_a' => 'Individual', + 'contact_type_b' => 'Organization', + ])['id']; + + $personToPersonType = 'A_B_alt_relationship'; + $personToPersonReverseType = 'B_A_alt_relationship'; + + civicrm_api3('RelationshipType', 'create', [ + 'name_a_b' => $personToPersonType, + 'name_b_a' => $personToPersonReverseType, + 'contact_type_a' => 'Individual', + 'contact_type_b' => 'Individual', + ]); + + // create a relationship individual => organization + $relationship = civicrm_api3('Relationship', 'create', [ + 'contact_id_a' => $individual['id'], + 'contact_id_b' => $organization['id'], + 'relationship_type_id' => $orgToPersonTypeId, + ]); + + $options = CRM_Contact_BAO_Relationship::buildRelationshipTypeOptions([ + 'relationship_id' => (string) $relationship['id'], + 'contact_id' => $individual['id'] + ]); + + // for this relationship only individual=>organization is possible + $this->assertContains($personToOrgType, $options); + $this->assertNotContains($orgToPersonType, $options); + + // by passing relationship ID we know that the "B" side is an organization + $this->assertNotContains($personToPersonType, $options); + $this->assertNotContains($personToPersonReverseType, $options); + + $options = CRM_Contact_BAO_Relationship::buildRelationshipTypeOptions([ + 'contact_id' => $individual['id'] + ]); + + // for this result we only know that "A" must be an individual + $this->assertContains($personToOrgType, $options); + $this->assertNotContains($orgToPersonType, $options); + + // unlike when we pass relationship type ID there is no filter by "B" type + $this->assertContains($personToPersonType, $options); + $this->assertContains($personToPersonReverseType, $options); + } + /** * Test removeRelationshipTypeDuplicates method. * -- 2.25.1