From 89e45979567e990d55222dea60e737252c086c60 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Wed, 21 Mar 2018 16:29:54 +0000 Subject: [PATCH 01/11] 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 29a2f7adebb2..bc6ea7ae5758 100644 --- a/CRM/Contact/BAO/Relationship.php +++ b/CRM/Contact/BAO/Relationship.php @@ -2149,4 +2149,73 @@ public static function getContactRelationshipSelector(&$params) { 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 4bb2d254edc2..9311d222e678 100644 --- a/tests/phpunit/CRM/Contact/BAO/RelationshipTest.php +++ b/tests/phpunit/CRM/Contact/BAO/RelationshipTest.php @@ -48,9 +48,102 @@ protected function setUp() { * 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. * From e003e69bbe8f6b8d0b81ff21cd3d1514e0ae30f4 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Wed, 21 Mar 2018 16:31:08 +0000 Subject: [PATCH 02/11] CRM-21849: Cast contact_id_a before comparison This property will be a string, but it is being compared to $contactID which should be an int. --- CRM/Contact/BAO/Relationship.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php index bc6ea7ae5758..2b4cd47e7cc6 100644 --- a/CRM/Contact/BAO/Relationship.php +++ b/CRM/Contact/BAO/Relationship.php @@ -539,7 +539,7 @@ public static function getContactRelationshipType( $relationship->id = $relationshipId; if ($relationship->find(TRUE)) { $contact = new CRM_Contact_DAO_Contact(); - $contact->id = ($relationship->contact_id_a === $contactId) ? $relationship->contact_id_b : $relationship->contact_id_a; + $contact->id = ((int) $relationship->contact_id_a === $contactId) ? $relationship->contact_id_b : $relationship->contact_id_a; if ($contact->find(TRUE)) { $otherContactType = $contact->contact_type; From b3ee84c91c79300ccc1ce0d3cbae83f5271e182f Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Wed, 21 Mar 2018 16:32:58 +0000 Subject: [PATCH 03/11] CRM-21849: Allow adding option_context to elements This is used when some extra parameters are required when refreshing option lists after inline editing, i.e. relationship types are limited to the current contact type --- CRM/Contact/Form/Relationship.php | 17 ++++++++++++++++- CRM/Core/Form.php | 6 ++++++ js/crm.optionEdit.js | 7 +++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CRM/Contact/Form/Relationship.php b/CRM/Contact/Form/Relationship.php index 3ef442ab9ea3..16932158ad09 100644 --- a/CRM/Contact/Form/Relationship.php +++ b/CRM/Contact/Form/Relationship.php @@ -309,7 +309,22 @@ public function buildQuickForm() { } } - $this->addField('relationship_type_id', array('options' => array('' => ts('- select -')) + $relationshipList, 'class' => 'huge', 'placeholder' => '- select -'), TRUE); + $this->addField( + 'relationship_type_id', + array( + 'options' => array('' => ts('- select -')) + $relationshipList, + 'class' => 'huge', + 'placeholder' => '- select -', + 'option_url' => 'civicrm/admin/reltype', + 'option_context' => array( + 'contact_id' => $this->_contactId, + 'relationship_direction' => $this->_rtype, + 'relationship_id' => $this->_relationshipId, + 'is_form' => TRUE, + ), + ), + TRUE + ); $label = $this->_action & CRM_Core_Action::ADD ? ts('Contact(s)') : ts('Contact'); $contactField = $this->addField('related_contact_id', array('label' => $label, 'name' => 'contact_id_b', 'multiple' => TRUE, 'create' => TRUE), TRUE); diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index 015b8390a7ca..d84189ee6ed9 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -408,6 +408,12 @@ public function &add( } } + // Add context for the editing of option groups + if (isset($extra['option_context'])) { + $context = json_encode($extra['option_context']); + $element->setAttribute('data-option-edit-context', $context); + } + return $element; } diff --git a/js/crm.optionEdit.js b/js/crm.optionEdit.js index 1b1338ce00a7..20e01b7afdcb 100644 --- a/js/crm.optionEdit.js +++ b/js/crm.optionEdit.js @@ -30,10 +30,13 @@ jQuery(function($) { */ function rebuildOptions($existing, rebuilder) { if ($existing.data('api-entity') && $existing.data('api-field')) { - CRM.api3($existing.data('api-entity'), 'getoptions', { + var params = { sequential: 1, field: $existing.data('api-field') - }) + }; + $.extend(params, $existing.data('option-edit-context')); + + CRM.api3($existing.data('api-entity'), 'getoptions', params) .done(function(data) { rebuilder($existing, data.values); }); From 3370a7b10e00db4a87416cd1a179bbcdce07cbe2 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Wed, 21 Mar 2018 16:33:52 +0000 Subject: [PATCH 04/11] CRM-21849: Allow spec modification for getoptions Allows to modify spec even if generic getoptions function is used --- api/v3/Generic.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/v3/Generic.php b/api/v3/Generic.php index b6d0bb1cac88..848d4731bc91 100644 --- a/api/v3/Generic.php +++ b/api/v3/Generic.php @@ -475,6 +475,13 @@ function _civicrm_api3_generic_getoptions_spec(&$params, $apiRequest) { } } } + + $entityName = _civicrm_api_get_entity_name_from_camel($apiRequest['entity']); + $getOptionsSpecFunction = '_civicrm_api3_' . $entityName . '_getoptions_spec'; + + if (function_exists($getOptionsSpecFunction)) { + $getOptionsSpecFunction($params); + } } /** From 44d259beb1ae9975587a8e5804424e736975c010 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Wed, 21 Mar 2018 16:34:11 +0000 Subject: [PATCH 05/11] CRM-21849: Add getoptions spec params for relationship_type_id --- api/v3/Relationship.php | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/api/v3/Relationship.php b/api/v3/Relationship.php index bab339b835ac..22cd6ddf0a30 100644 --- a/api/v3/Relationship.php +++ b/api/v3/Relationship.php @@ -169,3 +169,53 @@ function civicrm_api3_relationship_setvalue($params) { } return $result; } + +function _civicrm_api3_relationship_getoptions_spec(&$params) { + $params['field']['options']['relationship_type_id'] = ts('Relationship Type ID'); + + // Add parameters for limiting relationship type ID + $relationshipTypePrefix = ts('(For relationship_type_id only) '); + $params['contact_id'] = [ + 'title' => ts('Contact ID'), + 'description' => $relationshipTypePrefix . ts('Limits options to those' + . ' available to give contact'), + 'type' => CRM_Utils_Type::T_INT, + 'FKClassName' => 'CRM_Contact_DAO_Contact', + 'FKApiName' => 'Contact', + ]; + $params['relationship_direction'] = [ + 'title' => ts('Relationship Direction'), + 'description' => $relationshipTypePrefix . ts('For relationships where the ' + . 'name is the same for both sides (i.e. "Spouse Of") show the option ' + . 'from "A" (origin) side or "B" (target) side of the relationship?'), + 'type' => CRM_Utils_Type::T_STRING, + 'options' => ['a_b' => 'a_b', 'b_a' => 'b_a'], + 'api.default' => 'a_b', + ]; + $params['relationship_id'] = [ + 'title' => ts('Reference Relationship ID'), + 'description' => $relationshipTypePrefix . ts('If provided alongside ' + . 'contact ID it will be used to establish the contact type of the "B" ' + . 'side of the relationship and limit options based on it. If the ' + . 'provided contact ID does not match the "A" side of this relationship ' + . 'then the "A" side of this relationship will be used to limit options'), + 'type' => CRM_Utils_Type::T_INT, + 'FKClassName' => 'CRM_Contact_DAO_Relationship', + 'FKApiName' => 'Relationship', + ]; + $contactTypes = CRM_Contact_BAO_ContactType::contactTypes(); + $params['contact_type'] = [ + 'title' => ts('Contact Type'), + 'description' => $relationshipTypePrefix . ts('Limits options to those ' + . 'available to this contact type. Overridden by the contact type of ' + . 'contact ID (if provided)'), + 'type' => CRM_Utils_Type::T_STRING, + 'options' => array_combine($contactTypes, $contactTypes), + ]; + $params['is_form'] = [ + 'title' => ts('Is Form?'), + 'description' => $relationshipTypePrefix . ts('Formats the options for use' + . ' in a form if true. The format is <id>_a_b => <label>'), + 'type' => CRM_Utils_Type::T_BOOLEAN + ]; +} From b277f8d1539fc5736a6627430851b7c426c35e32 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Tue, 27 Mar 2018 14:43:56 +0100 Subject: [PATCH 06/11] CRM-21849: Change to loose comparison Based on the docblock I expected contact ID to be an int, but this is not always the case. --- CRM/Contact/BAO/Relationship.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php index 2b4cd47e7cc6..afad1081028b 100644 --- a/CRM/Contact/BAO/Relationship.php +++ b/CRM/Contact/BAO/Relationship.php @@ -539,7 +539,7 @@ public static function getContactRelationshipType( $relationship->id = $relationshipId; if ($relationship->find(TRUE)) { $contact = new CRM_Contact_DAO_Contact(); - $contact->id = ((int) $relationship->contact_id_a === $contactId) ? $relationship->contact_id_b : $relationship->contact_id_a; + $contact->id = ($relationship->contact_id_a == $contactId) ? $relationship->contact_id_b : $relationship->contact_id_a; if ($contact->find(TRUE)) { $otherContactType = $contact->contact_type; From a2f1945a81ef562f6ad0a4bf79cde9d1807543de Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Tue, 27 Mar 2018 16:06:09 +0100 Subject: [PATCH 07/11] CRM-21849: Include data in event after enable/disable The logic on whether to refresh the available options in CRM.popup depends on whether the crmPopupFormSuccess returned data. The data provided here is arbitrary but could be useful in the future for anyone reacting to the event --- templates/CRM/common/enableDisableApi.tpl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/templates/CRM/common/enableDisableApi.tpl b/templates/CRM/common/enableDisableApi.tpl index ed9f284247a5..8ab4bc889a8a 100644 --- a/templates/CRM/common/enableDisableApi.tpl +++ b/templates/CRM/common/enableDisableApi.tpl @@ -36,7 +36,13 @@ } function refresh() { - $a.trigger('crmPopupFormSuccess'); + // the opposite of the current status based on row class + var newStatus = $row.hasClass('disabled'); + $a.trigger('crmPopupFormSuccess', { + 'entity': info.entity, + 'id': info.id, + 'enabled': newStatus + }); CRM.refreshParent($row); } From 601cc898b1cc0bec9743a74b319e890db0bed98d Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Mon, 16 Apr 2018 13:06:05 +0100 Subject: [PATCH 08/11] CRM-21849: Switch loading relationship data from backend to frontend The formatting of relationship data is a FE related task and can be done in Javascript. This also allows reloading the data if some options change after editing relationship types. --- CRM/Contact/Form/Relationship.php | 3 - templates/CRM/Contact/Form/Relationship.tpl | 111 +++++++++++++++++++- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/CRM/Contact/Form/Relationship.php b/CRM/Contact/Form/Relationship.php index 16932158ad09..f4d9a1478119 100644 --- a/CRM/Contact/Form/Relationship.php +++ b/CRM/Contact/Form/Relationship.php @@ -299,9 +299,6 @@ public function buildQuickForm() { // Select list $relationshipList = CRM_Contact_BAO_Relationship::getContactRelationshipType($this->_contactId, $this->_rtype, $this->_relationshipId); - // Metadata needed on clientside - $this->assign('relationshipData', self::getRelationshipTypeMetadata($relationshipList)); - foreach ($this->_allRelationshipNames as $id => $vals) { if ($vals['name_a_b'] === 'Employee of') { $this->assign('employmentRelationship', $id); diff --git a/templates/CRM/Contact/Form/Relationship.tpl b/templates/CRM/Contact/Form/Relationship.tpl index 77a324401473..1c69d1032ef8 100644 --- a/templates/CRM/Contact/Form/Relationship.tpl +++ b/templates/CRM/Contact/Form/Relationship.tpl @@ -144,10 +144,113 @@ CRM.$(function($) { var $form = $("form.{/literal}{$form.formClass}{literal}"), - relationshipData = {/literal}{$relationshipData|@json_encode}{literal}; - $('[name=relationship_type_id]', $form).change(function() { + $relationshipTypeSelect = $('[name=relationship_type_id]', $form), + relationshipData = {}, + contactTypes = {}; + + $('body').on('crmOptionsEdited', 'a.crm-option-edit-link', refreshRelationshipData); + + // Initial load and trigger change on select + refreshRelationshipData().done(function() { + $relationshipTypeSelect.change(); + }); + + /** + * Fetch contact types and reset relationship data + */ + function refreshRelationshipData() { + var defer = $.Deferred(); + + // reset + relationshipData = {}; + + getContactTypes().then(function() { + getRelationshipData().then(function() { + defer.resolve(); + }); + }); + + return defer.promise(); + } + + /** + * Fetches the relationship data using latest relationship types + */ + function getRelationshipData() { + var subtype, + type, + label, + placeholder, + defer = $.Deferred(); + + if ($.isEmptyObject(relationshipData)) { + CRM.api3("RelationshipType", "get").done(function (data) { + $.each(data.values, function (key, relType) { + $.each(["a", "b"], function (index, suffix) { + subtype = relType["contact_subtype_" + suffix]; + type = subtype || relType["contact_type_" + suffix]; + label = getContactTypeLabel(type) || "Contact"; + placeholder = "- select " + label.toLowerCase() + " -"; + relType["placeholder_" + suffix] = placeholder; + }); + relationshipData[relType["id"]] = relType; + }); + + defer.resolve(relationshipData); + }); + } else { + defer.resolve(relationshipData); + } + + return defer.promise(); + } + + /** + * Gets a contact type label based on a provided name + * @param {String} name - the name of the contact type + */ + function getContactTypeLabel(name) { + var label = ""; + + $.each(contactTypes, function(index, contactType) { + if (contactType.name === name) { + label = contactType.label; + return false; + } + }); + + return label; + } + + /** + * Fetches contact types + */ + function getContactTypes() { + var defer = $.Deferred(); + if ($.isEmptyObject(contactTypes)) { + CRM.api3("ContactType", "get").done(function (data) { + contactTypes = data.values; + defer.resolve(contactTypes); + }); + } else { + defer.resolve(contactTypes); + } + + return defer.promise(); + } + + $relationshipTypeSelect.change(function() { + var $select = $(this); + + // ensure we have relationship data before changing anything + getRelationshipData().then(function() { + updateSelect($select); + }) + }); + + function updateSelect($select) { var - val = $(this).val(), + val = $select.val(), $contactField = $('#related_contact_id[type=text]', $form); if (!val && $contactField.length) { $contactField @@ -190,7 +293,7 @@ CRM.buildCustomData('Relationship', rType); } - }).change(); + } }); {/literal} From 6fe0a7d81a03937a06ca5a62b2c0d2c3efe29c93 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Mon, 16 Apr 2018 16:10:17 +0100 Subject: [PATCH 09/11] CRM-21849: Post-review cleanup --- templates/CRM/Contact/Form/Relationship.tpl | 68 ++++++++++----------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/templates/CRM/Contact/Form/Relationship.tpl b/templates/CRM/Contact/Form/Relationship.tpl index 1c69d1032ef8..df3a0579ffe2 100644 --- a/templates/CRM/Contact/Form/Relationship.tpl +++ b/templates/CRM/Contact/Form/Relationship.tpl @@ -148,59 +148,62 @@ relationshipData = {}, contactTypes = {}; - $('body').on('crmOptionsEdited', 'a.crm-option-edit-link', refreshRelationshipData); + (function init () { + // Refresh options if relationship types were edited + $('body').on('crmOptionsEdited', 'a.crm-option-edit-link', refreshRelationshipData); + // Initial load and trigger change on select + refreshRelationshipData().done(function() { + $relationshipTypeSelect.change(); + }); + $relationshipTypeSelect.change(function() { + var $select = $(this); - // Initial load and trigger change on select - refreshRelationshipData().done(function() { - $relationshipTypeSelect.change(); - }); + // ensure we have relationship data before changing anything + getRelationshipData().then(function() { + updateSelect($select); + }) + }); + })(); /** * Fetch contact types and reset relationship data */ function refreshRelationshipData() { - var defer = $.Deferred(); - // reset relationshipData = {}; - getContactTypes().then(function() { - getRelationshipData().then(function() { - defer.resolve(); - }); + return getContactTypes().then(function() { + return getRelationshipData(); }); - - return defer.promise(); } /** * Fetches the relationship data using latest relationship types */ function getRelationshipData() { - var subtype, - type, - label, - placeholder, - defer = $.Deferred(); + var defer = $.Deferred(); - if ($.isEmptyObject(relationshipData)) { - CRM.api3("RelationshipType", "get").done(function (data) { + if (!$.isEmptyObject(relationshipData)) { + defer.resolve(relationshipData); + } + + CRM.api3("RelationshipType", "get") + .done(function (data) { $.each(data.values, function (key, relType) { + // Loop over the suffixes for a relationship type $.each(["a", "b"], function (index, suffix) { - subtype = relType["contact_subtype_" + suffix]; - type = subtype || relType["contact_type_" + suffix]; - label = getContactTypeLabel(type) || "Contact"; - placeholder = "- select " + label.toLowerCase() + " -"; - relType["placeholder_" + suffix] = placeholder; + var subtype = relType["contact_subtype_" + suffix]; + var type = subtype || relType["contact_type_" + suffix]; + var label = getContactTypeLabel(type) || "Contact"; + var placeholder = "- select " + label.toLowerCase() + " -"; + relType["placeholder_" + suffix] = placeholder }); + relationshipData[relType["id"]] = relType; }); defer.resolve(relationshipData); }); - } else { - defer.resolve(relationshipData); - } return defer.promise(); } @@ -239,15 +242,6 @@ return defer.promise(); } - $relationshipTypeSelect.change(function() { - var $select = $(this); - - // ensure we have relationship data before changing anything - getRelationshipData().then(function() { - updateSelect($select); - }) - }); - function updateSelect($select) { var val = $select.val(), From 8e383c2f5cb1d8205d706eb687474d9f5f9c9d38 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Mon, 16 Apr 2018 16:33:38 +0100 Subject: [PATCH 10/11] CRM-21849: Load contactTypes in PHP, not JS --- CRM/Contact/Form/Relationship.php | 2 ++ templates/CRM/Contact/Form/Relationship.tpl | 27 +++------------------ 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/CRM/Contact/Form/Relationship.php b/CRM/Contact/Form/Relationship.php index f4d9a1478119..9d61ef486408 100644 --- a/CRM/Contact/Form/Relationship.php +++ b/CRM/Contact/Form/Relationship.php @@ -299,6 +299,8 @@ public function buildQuickForm() { // Select list $relationshipList = CRM_Contact_BAO_Relationship::getContactRelationshipType($this->_contactId, $this->_rtype, $this->_relationshipId); + $this->assign('contactTypes', CRM_Contact_BAO_ContactType::contactTypeInfo(TRUE)); + foreach ($this->_allRelationshipNames as $id => $vals) { if ($vals['name_a_b'] === 'Employee of') { $this->assign('employmentRelationship', $id); diff --git a/templates/CRM/Contact/Form/Relationship.tpl b/templates/CRM/Contact/Form/Relationship.tpl index df3a0579ffe2..d66d3969a22a 100644 --- a/templates/CRM/Contact/Form/Relationship.tpl +++ b/templates/CRM/Contact/Form/Relationship.tpl @@ -146,7 +146,7 @@ $form = $("form.{/literal}{$form.formClass}{literal}"), $relationshipTypeSelect = $('[name=relationship_type_id]', $form), relationshipData = {}, - contactTypes = {}; + contactTypes = {/literal}{$contactTypes|@json_encode}{literal}; (function init () { // Refresh options if relationship types were edited @@ -172,9 +172,7 @@ // reset relationshipData = {}; - return getContactTypes().then(function() { - return getRelationshipData(); - }); + return getRelationshipData(); } /** @@ -195,8 +193,8 @@ var subtype = relType["contact_subtype_" + suffix]; var type = subtype || relType["contact_type_" + suffix]; var label = getContactTypeLabel(type) || "Contact"; - var placeholder = "- select " + label.toLowerCase() + " -"; - relType["placeholder_" + suffix] = placeholder + label = label.toLowerCase(); + relType["placeholder_" + suffix] = "- select " + label + " -"; }); relationshipData[relType["id"]] = relType; @@ -225,23 +223,6 @@ return label; } - /** - * Fetches contact types - */ - function getContactTypes() { - var defer = $.Deferred(); - if ($.isEmptyObject(contactTypes)) { - CRM.api3("ContactType", "get").done(function (data) { - contactTypes = data.values; - defer.resolve(contactTypes); - }); - } else { - defer.resolve(contactTypes); - } - - return defer.promise(); - } - function updateSelect($select) { var val = $select.val(), From 265af90b9c07421b9931b64e3e8f92fa4acfae08 Mon Sep 17 00:00:00 2001 From: Michael Devery Date: Tue, 17 Apr 2018 09:50:28 +0100 Subject: [PATCH 11/11] CRM-21849: Remove limit on API call --- templates/CRM/Contact/Form/Relationship.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/CRM/Contact/Form/Relationship.tpl b/templates/CRM/Contact/Form/Relationship.tpl index d66d3969a22a..79c16e928976 100644 --- a/templates/CRM/Contact/Form/Relationship.tpl +++ b/templates/CRM/Contact/Form/Relationship.tpl @@ -185,7 +185,7 @@ defer.resolve(relationshipData); } - CRM.api3("RelationshipType", "get") + CRM.api3("RelationshipType", "get", {"options": {"limit":0}}) .done(function (data) { $.each(data.values, function (key, relType) { // Loop over the suffixes for a relationship type