From 9918928167acbcf20f864e8d09d4f4b396bf3dfe Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 8 Nov 2022 10:36:15 -0500 Subject: [PATCH] APIv4 - Add event to customize default SavedSearch for autocompletes Customize Case autocomplete --- Civi/Api4/Generic/AutocompleteAction.php | 52 +++++---- .../Autocomplete/CaseAutocompleteProvider.php | 102 ++++++++++++++++++ .../Subscriber/AutocompleteSubscriber.php | 2 +- 3 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php diff --git a/Civi/Api4/Generic/AutocompleteAction.php b/Civi/Api4/Generic/AutocompleteAction.php index d249960007..561201e09c 100644 --- a/Civi/Api4/Generic/AutocompleteAction.php +++ b/Civi/Api4/Generic/AutocompleteAction.php @@ -13,6 +13,7 @@ namespace Civi\Api4\Generic; use Civi\Api4\Utils\CoreUtil; +use Civi\Core\Event\GenericHookEvent; /** * Retrieve $ENTITIES for an autocomplete form field. @@ -119,6 +120,10 @@ class AutocompleteAction extends AbstractAction { if (!$this->savedSearch) { $this->savedSearch = ['api_entity' => $entityName]; + // Allow the default search to be modified + \Civi::dispatcher()->dispatch('civi.search.autocompleteDefault', GenericHookEvent::create([ + 'savedSearch' => &$this->savedSearch, + ])); } $this->loadSavedSearch(); $this->loadSearchDisplay(); @@ -133,10 +138,9 @@ class AutocompleteAction extends AbstractAction { $labelField = implode(',', array_unique(array_merge([$labelField], $this->getTokens($this->display['settings']['columns'][0]['rewrite'])))); } - $apiParams =& $this->savedSearch['api_params']; // Render mode: fetch by id if ($this->ids) { - $apiParams['where'][] = [$idField, 'IN', $this->ids]; + $this->savedSearch['api_params']['where'][] = [$idField, 'IN', $this->ids]; unset($this->display['settings']['pager']); $return = NULL; } @@ -148,23 +152,7 @@ class AutocompleteAction extends AbstractAction { $this->addFilter($labelField, $this->input); } - // Ensure SELECT param includes all fields & trusted filters - $select = [$idField]; - foreach ($this->display['settings']['columns'] as $column) { - if ($column['type'] === 'field') { - $select[] = $column['key']; - } - if (!empty($column['rewrite'])) { - $select = array_merge($select, $this->getTokens($column['rewrite'])); - } - } - foreach ($this->trustedFilters as $fields => $val) { - $select = array_merge($select, explode(',', $fields)); - } - if (!empty($this->display['settings']['color'])) { - $select[] = $this->display['settings']['color']; - } - $apiParams['select'] = array_unique(array_merge($apiParams['select'], $select)); + $this->augmentSelectClause($idField); $apiResult = \Civi\Api4\SearchDisplay::run(FALSE) ->setSavedSearch($this->savedSearch) @@ -202,6 +190,32 @@ class AutocompleteAction extends AbstractAction { $this->trustedFilters[$fieldName] = $value; } + /** + * Ensure SELECT param includes all display fields & trusted filters + * + * @param string $idField + */ + private function augmentSelectClause(string $idField) { + $select = [$idField]; + foreach ($this->display['settings']['columns'] as $column) { + if ($column['type'] === 'field') { + $select[] = $column['key']; + } + if (!empty($column['rewrite'])) { + $select = array_merge($select, $this->getTokens($column['rewrite'])); + } + } + // Add trustedFilters to the SELECT clause so that SearchDisplay::run will trust them + foreach ($this->trustedFilters as $fields => $val) { + $select = array_merge($select, explode(',', $fields)); + } + if (!empty($this->display['settings']['color'])) { + $select[] = $this->display['settings']['color']; + } + $select = array_merge($select, array_column($this->display['settings']['sort'] ?? [], 0)); + $this->savedSearch['api_params']['select'] = array_unique(array_merge($this->savedSearch['api_params']['select'], $select)); + } + /** * @param $fieldNameWithSuffix * @return bool diff --git a/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php b/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php new file mode 100644 index 0000000000..5bc7476b95 --- /dev/null +++ b/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php @@ -0,0 +1,102 @@ +savedSearch) || $e->savedSearch['api_entity'] !== 'Case') { + return; + } + $e->savedSearch['api_params'] = [ + 'version' => 4, + 'select' => [ + 'id', + 'subject', + 'Case_CaseContact_Contact_01.display_name', + 'case_type_id:label', + 'status_id:label', + 'start_date', + ], + 'orderBy' => [], + 'where' => [], + 'groupBy' => [], + 'join' => [ + [ + 'Contact AS Case_CaseContact_Contact_01', + 'LEFT', + 'CaseContact', + ['id', '=', 'Case_CaseContact_Contact_01.case_id'], + ], + ], + 'having' => [], + ]; + } + + /** + * Provide default SearchDisplay for Case autocompletes + * + * @param \Civi\Core\Event\GenericHookEvent $e + */ + public static function on_civi_search_defaultDisplay(GenericHookEvent $e) { + if ($e->display['settings'] || $e->display['type'] !== 'autocomplete' || $e->savedSearch['api_entity'] !== 'Case') { + return; + } + // Basic settings with no join + // We won't assume the SavedSearch includes a contact join, because it's possible to override + // the savedSearch for an autocomplete and still use this default display. + $e->display['settings'] = [ + 'sort' => [ + ['subject', 'ASC'], + ], + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'subject', + ], + [ + 'type' => 'field', + 'key' => 'id', + 'rewrite' => '#[id]: [case_type_id:label]', + ], + [ + 'type' => 'field', + 'key' => 'status_id:label', + 'rewrite' => '[status_id:label] (' . ts('Started %1', [1 => '[start_date]']) . ')', + ], + ], + ]; + // If the savedSearch includes a contact join, add it to the output and the sort. + foreach ($e->savedSearch['api_params']['join'] ?? [] as $join) { + [$entity, $contactAlias] = explode(' AS ', $join[0]); + if ($entity === 'Contact') { + array_unshift($e->display['settings']['sort'], ["$contactAlias.sort_name", 'ASC']); + $e->display['settings']['columns'][0]['rewrite'] = "[$contactAlias.display_name] - [subject]"; + break; + } + } + } + +} diff --git a/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php b/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php index 7c8bb97f4b..88af00a26f 100644 --- a/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php +++ b/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php @@ -78,7 +78,7 @@ class AutocompleteSubscriber implements EventSubscriberInterface { $fieldSpec = civicrm_api4($entity['type'], 'getFields', [ 'checkPermissions' => FALSE, 'where' => [['name', '=', $fieldName]], - ])->single(); + ])->first(); $formField = $entity['fields'][$fieldName]['defn'] ?? []; // Auto-add filters defined in schema -- 2.25.1