From 4d3319189a17468851e65793aa123306382ac745 Mon Sep 17 00:00:00 2001 From: colemanw Date: Tue, 19 Dec 2023 22:22:06 -0500 Subject: [PATCH] SearchKit - Consolidate getJoins, add tests --- ext/search_kit/Civi/Search/Admin.php | 89 +++++++------------ .../tests/phpunit/Civi/Search/AdminTest.php | 61 +++++++++++-- 2 files changed, 82 insertions(+), 68 deletions(-) diff --git a/ext/search_kit/Civi/Search/Admin.php b/ext/search_kit/Civi/Search/Admin.php index 44fd79ba40..ccad5f42ac 100644 --- a/ext/search_kit/Civi/Search/Admin.php +++ b/ext/search_kit/Civi/Search/Admin.php @@ -282,56 +282,10 @@ class Admin { public static function getJoins(array $allowedEntities):array { $joins = []; foreach ($allowedEntities as $entity) { - // Multi-record custom field groups (to-date only the contact entity supports these) - if (in_array('CustomValue', $entity['type'])) { - // TODO: Lookup target entity from custom group if someday other entities support multi-record custom data - $targetEntity = $allowedEntities['Contact']; - // Join from Custom group to Contact (n-1) - $alias = "{$entity['name']}_{$targetEntity['name']}_entity_id"; - $joins[$entity['name']][] = [ - 'label' => $entity['title'] . ' ' . $targetEntity['title'], - 'description' => '', - 'entity' => $targetEntity['name'], - 'conditions' => self::getJoinConditions('entity_id', $alias . '.id'), - 'defaults' => self::getJoinDefaults($alias, $targetEntity), - 'alias' => $alias, - 'multi' => FALSE, - ]; - // Join from Contact to Custom group (n-n) - $alias = "{$targetEntity['name']}_{$entity['name']}_entity_id"; - $joins[$targetEntity['name']][] = [ - 'label' => $entity['title_plural'], - 'description' => '', - 'entity' => $entity['name'], - 'conditions' => self::getJoinConditions('id', $alias . '.entity_id'), - 'defaults' => self::getJoinDefaults($alias, $entity), - 'alias' => $alias, - 'multi' => TRUE, - ]; - - // Allow joins via EntityRef fields in multi-value custom data - foreach ($entity['fields'] as $field) { - // Note: we skip entity_id field since it is handled below. - if ($field['input_type'] === 'EntityRef' && $field['name'] !== 'entity_id') { - - // Join from the custom data entity to the referenced entity - $joins[$entity['name']][] = self::getEntityRefJoins($entity, $field); + $isCustomEntity = in_array('CustomValue', $entity['type'], TRUE); - // Join from referenced entity to the custom data entity - $joins[$field['fk_entity']][] = [ - 'label' => $entity["title_plural"], - 'description' => $entity["description"], - 'entity' => $entity["name"], - 'conditions' => [], - 'defaults' => [], - 'alias' => $entity['name'], - 'multi' => TRUE, - ]; - } - } - } // Non-custom DAO entities - elseif (!empty($entity['dao'])) { + if (!$isCustomEntity && !empty($entity['dao'])) { /** @var \CRM_Core_DAO $daoClass */ $daoClass = $entity['dao']; $references = $daoClass::getReferenceColumns(); @@ -443,10 +397,14 @@ class Admin { } } } - // Custom EntityRef joins - foreach ($fields as $field) { - if ($field['type'] === 'Custom' && $field['input_type'] === 'EntityRef') { - $joins[$entity['name']][] = self::getEntityRefJoins($entity, $field); + } + + // Custom EntityRef joins + foreach ($entity['fields'] as $field) { + if (($field['type'] === 'Custom' || $isCustomEntity) && $field['fk_entity'] && $field['input_type'] === 'EntityRef') { + $entityRefJoins = self::getEntityRefJoins($entity, $field); + foreach ($entityRefJoins as $joinEntity => $joinInfo) { + $joins[$joinEntity][] = $joinInfo; } } } @@ -455,16 +413,16 @@ class Admin { } /** - * Get a join for an entity reference + * Get joins for entity reference custom fields, and the entity_id fields in multi-record custom groups. * - * @return void + * @return array[] */ - public static function getEntityRefJoins($entity, $field) { + public static function getEntityRefJoins(array $entity, array $field): array { $exploded = explode('.', $field['name']); $bareFieldName = array_reverse($exploded)[0]; - $alias = $entity['name'] . '_' . $field['fk_entity'] . '_' . $bareFieldName; - $join = [ - 'label' => $entity['title'] . ' ' . $field['title'], + $alias = "{$entity['name']}_{$field['fk_entity']}_$bareFieldName"; + $joins[$entity['name']] = [ + 'label' => $entity['title'] . ' ' . $field['label'], 'description' => $field['description'], 'entity' => $field['fk_entity'], 'conditions' => self::getJoinConditions($field['name'], $alias . '.id'), @@ -472,7 +430,20 @@ class Admin { 'alias' => $alias, 'multi' => FALSE, ]; - return $join; + // Do reverse join if not the same entity + if ($entity['name'] !== $field['fk_entity']) { + $alias = "{$field['fk_entity']}_{$entity['name']}_$bareFieldName"; + $joins[$field['fk_entity']] = [ + 'label' => $entity['title_plural'], + 'description' => $entity['description'], + 'entity' => $entity['name'], + 'conditions' => self::getJoinConditions('id', "$alias.{$field['name']}"), + 'defaults' => [], + 'alias' => $alias, + 'multi' => TRUE, + ]; + } + return $joins; } /** diff --git a/ext/search_kit/tests/phpunit/Civi/Search/AdminTest.php b/ext/search_kit/tests/phpunit/Civi/Search/AdminTest.php index 7093a165ec..2902241644 100644 --- a/ext/search_kit/tests/phpunit/Civi/Search/AdminTest.php +++ b/ext/search_kit/tests/phpunit/Civi/Search/AdminTest.php @@ -1,15 +1,17 @@ installMe(__DIR__)->apply(); } @@ -127,21 +129,62 @@ class AdminTest extends \PHPUnit\Framework\TestCase implements HeadlessInterface } public function testEntityRefGetJoins(): void { - \Civi\Api4\CustomGroup::create()->setValues([ + $this->createTestRecord('CustomGroup', [ 'title' => 'EntityRefFields', 'extends' => 'Individual', - ])->execute(); - \Civi\Api4\CustomField::create()->setValues([ + ]); + $this->createTestRecord('CustomField', [ 'label' => 'Favorite Nephew', 'name' => 'favorite_nephew', 'custom_group_id.name' => 'EntityRefFields', 'html_type' => 'Autocomplete-Select', 'data_type' => 'EntityReference', 'fk_entity' => 'Contact', - ])->execute(); + ]); + $allowedEntities = Admin::getSchema(); + $joins = Admin::getJoins($allowedEntities); + + $entityRefJoin = \CRM_Utils_Array::findAll($joins['Contact'], ['alias' => 'Contact_Contact_favorite_nephew']); + $this->assertCount(1, $entityRefJoin); + $this->assertEquals([['EntityRefFields.favorite_nephew', '=', 'Contact_Contact_favorite_nephew.id']], $entityRefJoin[0]['conditions']); + $this->assertStringContainsString('Favorite Nephew', $entityRefJoin[0]['label']); + } + + public function testMultiRecordCustomGetJoins(): void { + $this->createTestRecord('CustomGroup', [ + 'title' => 'Multiple Things', + 'name' => 'MultiRecordActivity', + 'extends' => 'Activity', + 'is_multiple' => TRUE, + ]); + $this->createTestRecord('CustomField', [ + 'label' => 'Ref Group', + 'name' => 'ref_group', + 'custom_group_id.name' => 'MultiRecordActivity', + 'html_type' => 'Autocomplete-Select', + 'data_type' => 'EntityReference', + 'fk_entity' => 'Group', + ]); $allowedEntities = Admin::getSchema(); $joins = Admin::getJoins($allowedEntities); - $this->assertContains('Contact Favorite Nephew', array_column($joins['Contact'], 'label')); + + $entityRefJoin = \CRM_Utils_Array::findAll($joins['Custom_MultiRecordActivity'], ['alias' => 'Custom_MultiRecordActivity_Group_ref_group']); + $this->assertCount(1, $entityRefJoin); + $this->assertEquals([['ref_group', '=', 'Custom_MultiRecordActivity_Group_ref_group.id']], $entityRefJoin[0]['conditions']); + + $reverseJoin = \CRM_Utils_Array::findAll($joins['Group'], ['alias' => 'Group_Custom_MultiRecordActivity_ref_group']); + $this->assertCount(1, $reverseJoin); + $this->assertEquals([['id', '=', 'Group_Custom_MultiRecordActivity_ref_group.ref_group']], $reverseJoin[0]['conditions']); + + $activityToCustomJoin = \CRM_Utils_Array::findAll($joins['Activity'], ['alias' => 'Activity_Custom_MultiRecordActivity_entity_id']); + $this->assertCount(1, $activityToCustomJoin); + $this->assertEquals([['id', '=', 'Activity_Custom_MultiRecordActivity_entity_id.entity_id']], $activityToCustomJoin[0]['conditions']); + $this->assertEquals('Multiple Things', $activityToCustomJoin[0]['label']); + + $customToActivityJoin = \CRM_Utils_Array::findAll($joins['Custom_MultiRecordActivity'], ['alias' => 'Custom_MultiRecordActivity_Activity_entity_id']); + $this->assertCount(1, $customToActivityJoin); + $this->assertEquals([['entity_id', '=', 'Custom_MultiRecordActivity_Activity_entity_id.id']], $customToActivityJoin[0]['conditions']); + $this->assertEquals('Multiple Things Activity', $customToActivityJoin[0]['label']); } } -- 2.25.1