* @param \Civi\API\Event\PrepareEvent $event
* API preparation event.
*/
- public function onApiPrepare(\Civi\API\Event\PrepareEvent $event) {
+ public function onApiPrepare(\Civi\API\Event\PrepareEvent $event): void {
$apiRequest = $event->getApiRequest();
if (is_object($apiRequest) && is_a($apiRequest, 'Civi\Api4\Generic\AutocompleteAction')) {
- $formName = $apiRequest->getFormName();
- if (!str_starts_with((string) $formName, 'afform:') || !strpos((string) $apiRequest->getFieldName(), ':')) {
- return;
- }
- [$entityName, $fieldName] = explode(':', $apiRequest->getFieldName());
- // Load afform only if user has permission
- $afform = Afform::get()
- ->addWhere('name', '=', str_replace('afform:', '', $formName))
- ->addSelect('layout')
- ->execute()->first();
- if (!$afform) {
- return;
+ [$formType, $formName] = array_pad(explode(':', (string) $apiRequest->getFormName()), 2, '');
+ [$entityName, $fieldName] = array_pad(explode(':', (string) $apiRequest->getFieldName()), 2, '');
+
+ switch ($formType) {
+ case 'afform':
+ if ($formName && $entityName && $fieldName) {
+ $this->processAfformAutocomplete($formName, $entityName, $fieldName, $apiRequest);
+ }
+ return;
+
+ case 'afformAdmin':
+ $this->processAfformAdminAutocomplete($entityName, $apiRequest);
}
- $formDataModel = new FormDataModel($afform['layout']);
- $entity = $formDataModel->getEntity($entityName);
+ }
+ }
- // Look up the "type" fields (e.g. contact_type, activity_type_id, case_type_id, etc)
- $typeFields = [];
+ /**
+ * Preprocess autocomplete fields for afforms
+ *
+ * @param string $formName
+ * @param string $entityName
+ * @param string $fieldName
+ * @param \Civi\Api4\Generic\AutocompleteAction $apiRequest
+ */
+ private function processAfformAutocomplete(string $formName, string $entityName, string $fieldName, AutocompleteAction $apiRequest):void {
+ // Load afform only if user has permission
+ $afform = Afform::get()
+ ->addWhere('name', '=', $formName)
+ ->addSelect('layout')
+ ->execute()->first();
+ if (!$afform) {
+ return;
+ }
+ $formDataModel = new FormDataModel($afform['layout']);
+ [$entityName, $joinEntity] = array_pad(explode('+', $entityName), 2, NULL);
+ $entity = $formDataModel->getEntity($entityName);
+
+ // If using a join (e.g. Contact -> Email)
+ if ($joinEntity) {
+ $apiEntity = $joinEntity;
+ $isId = FALSE;
+ $formField = $entity['joins'][$joinEntity]['fields'][$fieldName]['defn'] ?? [];
+ }
+ else {
+ $apiEntity = $entity['type'];
+ $isId = $fieldName === CoreUtil::getIdFieldName($apiEntity);
+ $formField = $entity['fields'][$fieldName]['defn'] ?? [];
+ }
+ $fieldSpec = civicrm_api4($apiEntity, 'getFields', [
+ 'checkPermissions' => FALSE,
+ 'where' => [['name', '=', $fieldName]],
+ ])->first();
+
+ // Auto-add filters defined in schema
+ foreach ($fieldSpec['input_attrs']['filter'] ?? [] as $key => $value) {
+ $apiRequest->addFilter($key, $value);
+ }
+
+ // For the "Existing Entity" selector,
+ // Look up the "type" fields (e.g. contact_type, activity_type_id, case_type_id, etc)
+ // And apply it as a filter if specified on the form.
+ if ($isId) {
if ($entity['type'] === 'Contact') {
$typeFields = ['contact_type', 'contact_sub_type'];
}