From 29a5acec48dfa883abc2817e4c1c47230dc28afc Mon Sep 17 00:00:00 2001 From: colemanw Date: Mon, 8 Jan 2024 21:00:53 -0500 Subject: [PATCH] APIv4 - Improve getFields internal value lookups --- Civi/Api4/Service/Spec/RequestSpec.php | 52 ++++++++++++++----- .../v4/Custom/CustomFieldGetFieldsTest.php | 18 ++++++- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Civi/Api4/Service/Spec/RequestSpec.php b/Civi/Api4/Service/Spec/RequestSpec.php index 64c259b3cf68..67ebdd63ff10 100644 --- a/Civi/Api4/Service/Spec/RequestSpec.php +++ b/Civi/Api4/Service/Spec/RequestSpec.php @@ -57,25 +57,51 @@ public function __construct(string $entity, string $action, array $values = []) $this->entity = $entity; $this->action = $action; $this->entityTableName = CoreUtil::getTableName($entity); + $this->values = $this->resolveValues($values); + } - // If `id` given, lookup other values needed to filter custom fields - $customInfo = \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends($entity); + /** + * Resolve as many values as possible based on available data + */ + private function resolveValues(array $values) { + if (!$values) { + return $values; + } + $customInfo = \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends($this->entity); $idCol = $customInfo['column'] ?? NULL; - if ($idCol && !empty($values[$idCol])) { - $grouping = (array) $customInfo['grouping']; - $lookupNeeded = array_diff($grouping, array_keys($values)); - if ($lookupNeeded) { - $record = \civicrm_api4($entity, 'get', [ + $grouping = (array) ($customInfo['grouping'] ?? []); + $lookupNeeded = array_diff($grouping, array_keys($values)); + // If `id` given, use that first + if ($lookupNeeded && $idCol && !empty($values[$idCol])) { + $record = \civicrm_api4($this->entity, 'get', [ + 'checkPermissions' => FALSE, + 'where' => [[$idCol, '=', $values[$idCol]]], + 'select' => $lookupNeeded, + ])->first(); + if ($record) { + $values += $record; + } + } + $lookupNeeded = array_diff($grouping, array_keys($values)); + foreach ($lookupNeeded as $fieldName) { + // If we need a value like `event_id.event_type_id` and we only have `event_id`, + // use the FK to lookup the value from the event. + if (str_contains($fieldName, '.')) { + [$fkFrom, $fkTo] = explode('.', $fieldName); + $fkEntity = \civicrm_api4($this->entity, 'getFields', [ 'checkPermissions' => FALSE, - 'where' => [[$idCol, '=', $values[$idCol]]], - 'select' => $lookupNeeded, - ])->first(); - if ($record) { - $values += $record; + 'where' => [['name', '=', $fkFrom]], + ])->first()['fk_entity'] ?? NULL; + if (!empty($values[$fkFrom]) && $fkEntity) { + $values[$fieldName] = \civicrm_api4($fkEntity, 'get', [ + 'checkPermissions' => FALSE, + 'where' => [['id', '=', $values[$fkFrom]]], + 'select' => [$fkTo], + ])->first()[$fkTo] ?? NULL; } } } - $this->values = $values; + return $values; } /** diff --git a/tests/phpunit/api/v4/Custom/CustomFieldGetFieldsTest.php b/tests/phpunit/api/v4/Custom/CustomFieldGetFieldsTest.php index a9549477bb38..3a30912b48c6 100644 --- a/tests/phpunit/api/v4/Custom/CustomFieldGetFieldsTest.php +++ b/tests/phpunit/api/v4/Custom/CustomFieldGetFieldsTest.php @@ -221,7 +221,7 @@ public function testCustomGetFieldsForParticipantSubTypes(): void { ->setRecords($sampleData) ->execute(); - // CustomGroup based on Event Type + // CustomGroup based on Event Type = Meeting|Conference CustomGroup::create(FALSE) ->addValue('extends', 'Participant') ->addValue('extends_entity_column_id:name', 'ParticipantEventType') @@ -234,7 +234,7 @@ public function testCustomGetFieldsForParticipantSubTypes(): void { ) ->execute(); - // CustomGroup based on Participant Status + // CustomGroup based on Participant Role CustomGroup::create(FALSE) ->addValue('extends', 'Participant') ->addValue('extends_entity_column_id:name', 'ParticipantRole') @@ -307,6 +307,20 @@ public function testCustomGetFieldsForParticipantSubTypes(): void { $this->assertArrayHasKey('volunteer_host.sub_field', $participant3Fields); $this->assertArrayNotHasKey('event_3_and_3.sub_field', $participant3Fields); $this->assertArrayHasKey('always.on', $participant3Fields); + + $event1Fields = Participant::getFields(FALSE) + ->addValue('event_id', $event1['id']) + ->execute()->indexBy('name'); + $this->assertArrayHasKey('meeting_conference.sub_field', $event1Fields); + $this->assertArrayNotHasKey('event_2_and_3.sub_field', $event1Fields); + $this->assertArrayHasKey('always.on', $event1Fields); + + $event4Fields = Participant::getFields(FALSE) + ->addValue('event_id', $event4['id']) + ->execute()->indexBy('name'); + $this->assertArrayNotHasKey('meeting_conference.sub_field', $event4Fields); + $this->assertArrayNotHasKey('event_3_and_3.sub_field', $event4Fields); + $this->assertArrayHasKey('always.on', $event4Fields); } public function testFiltersAreReturnedForContactRefFields(): void {