diff --git a/CRM/Contact/Page/View/Summary.php b/CRM/Contact/Page/View/Summary.php index 3112a4ad70e8..0389b5b24428 100644 --- a/CRM/Contact/Page/View/Summary.php +++ b/CRM/Contact/Page/View/Summary.php @@ -425,6 +425,14 @@ public function getTabs(array $contact) { ]; CRM_Utils_Hook::tabset('civicrm/contact/view', $allTabs, $context); + // Remove any tabs that don't apply to this contact type + foreach (array_keys($allTabs) as $key) { + $tabContactType = (array) ($allTabs[$key]['contact_type'] ?? []); + if ($tabContactType && !in_array($contact['contact_type'], $tabContactType, TRUE)) { + unset($allTabs[$key]); + } + } + $expectedKeys = ['count', 'class', 'template', 'hideCount', 'icon']; foreach ($allTabs as &$tab) { diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index 2b085cbe1684..e72f2eca212f 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -214,7 +214,7 @@ function afform_civicrm_tabset($tabsetName, &$tabs, $context) { if ($tabsetName !== 'civicrm/contact/view') { return; } - $contactTypes = array_merge([$context['contact_type']], $context['contact_sub_type'] ?? []); + $contactTypes = array_merge([$context['contact_type']] ?? [], $context['contact_sub_type'] ?? []); $afforms = Civi\Api4\Afform::get(FALSE) ->addSelect('name', 'title', 'icon', 'module_name', 'directive_name', 'summary_contact_type') ->addWhere('contact_summary', '=', 'tab') @@ -222,13 +222,15 @@ function afform_civicrm_tabset($tabsetName, &$tabs, $context) { ->execute(); $weight = 111; foreach ($afforms as $afform) { - if (empty($afform['summary_contact_type']) || array_intersect($afform['summary_contact_type'], $contactTypes)) { + $summaryContactType = $afform['summary_contact_type'] ?? []; + if (!$summaryContactType || !$contactTypes || array_intersect($summaryContactType, $contactTypes)) { $tabs[] = [ 'id' => $afform['name'], 'title' => $afform['title'], 'weight' => $weight++, 'icon' => 'crm-i ' . ($afform['icon'] ?: 'fa-list-alt'), 'is_active' => TRUE, + 'contact_type' => _afform_get_contact_types($summaryContactType) ?: NULL, 'template' => 'afform/contactSummary/AfformTab.tpl', 'module' => $afform['module_name'], 'directive' => $afform['directive_name'], @@ -298,7 +300,6 @@ function afform_civicrm_contactSummaryBlocks(&$blocks) { ->addWhere('contact_summary', '=', 'block') ->addOrderBy('title') ->execute(); - $allContactTypes = \CRM_Contact_BAO_ContactType::getAllContactTypes(); foreach ($afforms as $index => $afform) { // Create a group per afform type $blocks += [ @@ -308,17 +309,12 @@ function afform_civicrm_contactSummaryBlocks(&$blocks) { 'blocks' => [], ], ]; - $contactType = []; // If the form specifies contact types, resolve them to just the parent types (Individual, Organization, Household) // because ContactLayout doesn't care about sub-types - foreach ($afform['summary_contact_type'] ?? [] as $name) { - $parent = $allContactTypes[$name]['parent'] ?? $name; - $contactType[$parent] = $parent; - } + $contactType = _afform_get_contact_types($afform['summary_contact_type'] ?? []); $blocks["afform_{$afform['type']}"]['blocks'][$afform['name']] = [ 'title' => $afform['title'], - // ContactLayout only supports a single contact type - 'contact_type' => count($contactType) === 1 ? CRM_Utils_Array::first($contactType) : NULL, + 'contact_type' => $contactType ?: NULL, 'tpl_file' => 'afform/contactSummary/AfformBlock.tpl', 'module' => $afform['module_name'], 'directive' => $afform['directive_name'], @@ -331,6 +327,23 @@ function afform_civicrm_contactSummaryBlocks(&$blocks) { } } +/** + * Resolve a mixed list of contact types and sub-types into just top-level contact types (Individual, Organization, Household) + * + * @param array $mixedTypes + * @return array + * @throws CRM_Core_Exception + */ +function _afform_get_contact_types(array $mixedTypes): array { + $allContactTypes = \CRM_Contact_BAO_ContactType::getAllContactTypes(); + $contactTypes = []; + foreach ($mixedTypes as $name) { + $parent = $allContactTypes[$name]['parent'] ?? $name; + $contactTypes[$parent] = $parent; + } + return array_values($contactTypes); +} + /** * Implements hook_civicrm_angularModules(). * diff --git a/ext/afform/core/tests/phpunit/Civi/Afform/AfformContactSummaryTest.php b/ext/afform/core/tests/phpunit/Civi/Afform/AfformContactSummaryTest.php index 3b892aed15e7..21aafaeb5ffb 100644 --- a/ext/afform/core/tests/phpunit/Civi/Afform/AfformContactSummaryTest.php +++ b/ext/afform/core/tests/phpunit/Civi/Afform/AfformContactSummaryTest.php @@ -15,6 +15,8 @@ class AfformContactSummaryTest extends \api\v4\Api4TestBase { 'contact_summary_test1', 'contact_summary_test2', 'contact_summary_test3', + 'contact_summary_test4', + 'contact_summary_test5', ]; public function setUpHeadless() { @@ -52,6 +54,16 @@ public function testAfformContactSummaryTab(): void { ->addValue('title', 'Test A') ->addValue('contact_summary', 'tab') ->execute(); + Afform::create() + ->addValue('name', $this->formNames[3]) + ->addValue('title', 'Test D') + ->addValue('contact_summary', 'tab') + ->addValue('summary_contact_type', ['Individual']) + ->execute(); + Afform::create() + ->addValue('name', $this->formNames[4]) + ->addValue('title', 'Test E') + ->execute(); $tabs = []; $context = [ @@ -67,7 +79,11 @@ public function testAfformContactSummaryTab(): void { $this->assertArrayHasKey($this->formNames[1], $tabs); $this->assertArrayHasKey($this->formNames[2], $tabs); $this->assertArrayNotHasKey($this->formNames[0], $tabs); + $this->assertArrayHasKey($this->formNames[3], $tabs); + $this->assertArrayNotHasKey($this->formNames[4], $tabs); $this->assertEquals('Test C', $tabs[$this->formNames[1]]['title']); + $this->assertEquals(['Individual'], $tabs[$this->formNames[1]]['contact_type']); + $this->assertEquals(['Individual'], $tabs[$this->formNames[3]]['contact_type']); $this->assertEquals('Test A', $tabs[$this->formNames[2]]['title']); $this->assertEquals('crm-i smiley-face', $tabs[$this->formNames[1]]['icon']); // Fallback icon @@ -132,10 +148,9 @@ public function testAfformContactSummaryBlock(): void { $blocks = []; afform_civicrm_contactSummaryBlocks($blocks); - // ContactLayout doesn't support > 1 contact type, so this ought to be null - $this->assertNull($blocks['afform_search']['blocks'][$this->formNames[0]]['contact_type']); + $this->assertEquals(['Individual', 'Household'], $blocks['afform_search']['blocks'][$this->formNames[0]]['contact_type']); // Sub-type should have been converted to parent type - $this->assertEquals('Organization', $blocks['afform_form']['blocks'][$this->formNames[1]]['contact_type']); + $this->assertEquals(['Organization'], $blocks['afform_form']['blocks'][$this->formNames[1]]['contact_type']); $this->assertNull($blocks['afform_form']['blocks'][$this->formNames[2]]['contact_type']); // Forms should be sorted by title $order = array_flip(array_keys($blocks['afform_form']['blocks']));