Afform - Add autocomplete field
authorColeman Watts <coleman@civicrm.org>
Wed, 3 Aug 2022 18:32:54 +0000 (14:32 -0400)
committerColeman Watts <coleman@civicrm.org>
Wed, 10 Aug 2022 02:28:44 +0000 (22:28 -0400)
ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php
ext/afform/admin/Civi/Api4/Action/Afform/LoadAdminData.php
ext/afform/admin/ang/afGuiEditor/elements/afGuiField.component.js
ext/afform/core/Civi/Afform/FormDataModel.php
ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php [new file with mode: 0644]
ext/afform/core/afform.php

index a0f4b9061c053bd878f969d616c54e49e56a208b..566a5d387c320bcf0a02f36f4b6dffbe110ed7f3 100644 (file)
@@ -87,7 +87,7 @@ class AfformAdminMeta {
     $params += [
       'checkPermissions' => FALSE,
       'loadOptions' => ['id', 'label'],
-      'action' => 'create',
+      'action' => 'update',
       'select' => ['name', 'label', 'input_type', 'input_attrs', 'required', 'options', 'help_pre', 'help_post', 'serialize', 'data_type', 'fk_entity', 'readonly'],
       'where' => [['input_type', 'IS NOT NULL']],
     ];
@@ -123,8 +123,14 @@ class AfformAdminMeta {
     }
     // Index by name
     $fields = array_column($fields, NULL, 'name');
-    // Mix in alterations declared by afform entities
-    if ($params['action'] === 'create') {
+    if ($params['action'] === 'update') {
+      // Add existing entity field
+      $idField = CoreUtil::getIdFieldName($entityName);
+      $fields[$idField]['readonly'] = FALSE;
+      $fields[$idField]['input_type'] = 'EntityRef';
+      $fields[$idField]['is_id'] = TRUE;
+      $fields[$idField]['label'] = E::ts('Existing %1', [1 => CoreUtil::getInfoItem($entityName, 'title')]);
+      // Mix in alterations declared by afform entities
       $afEntity = self::getMetadata()['entities'][$entityName] ?? [];
       if (!empty($afEntity['alterFields'])) {
         foreach ($afEntity['alterFields'] as $fieldName => $changes) {
index db70363cdce744b6be979f8edce3785bae2e62aa..1bcba815522715aec1f5f9efea9013c9331ad469 100644 (file)
@@ -83,7 +83,7 @@ class LoadAdminData extends \Civi\Api4\Generic\AbstractAction {
       }
     }
 
-    $getFieldsMode = 'create';
+    $getFieldsMode = 'update';
 
     // Generate list of possibly embedded afform tags to search for
     $allAfforms = \Civi::service('afform_scanner')->findFilePaths();
index 0102c32e9bf1dd73e46337d8b9ffdea47a84d7a3..aacb628252a5fc6f9a0e22d4a75605f52702cb96 100644 (file)
@@ -52,7 +52,8 @@
       };
 
       this.getFkEntity = function() {
-        var fkEntity = ctrl.getDefn().fk_entity;
+        var defn = ctrl.getDefn(),
+          fkEntity = defn.is_id ? ctrl.container.getMainEntityType() : defn.fk_entity;
         return ctrl.editor.meta.entities[fkEntity];
       };
 
index a36872826260b1e3623b61bbe0b9579c9715e422..8d99733f8cd46adcde69f7cc80e6ed4f25a378ed 100644 (file)
@@ -50,7 +50,7 @@ class FormDataModel {
       $this->entities[$entity]['fields'] = $this->entities[$entity]['joins'] = [];
     }
     // Pre-load full list of afforms in case this layout embeds other afform directives
-    $this->blocks = (array) Afform::get()->setCheckPermissions(FALSE)->setSelect(['name', 'directive_name'])->execute()->indexBy('directive_name');
+    $this->blocks = (array) Afform::get(FALSE)->setSelect(['name', 'directive_name'])->execute()->indexBy('directive_name');
     $this->parseFields($layout);
   }
 
@@ -171,7 +171,7 @@ class FormDataModel {
       // Recurse into embedded blocks
       if (isset($this->blocks[$node['#tag']])) {
         if (!isset($this->blocks[$node['#tag']]['layout'])) {
-          $this->blocks[$node['#tag']] = Afform::get()->setCheckPermissions(FALSE)->setSelect(['name', 'layout'])->addWhere('name', '=', $this->blocks[$node['#tag']]['name'])->execute()->first();
+          $this->blocks[$node['#tag']] = Afform::get(FALSE)->setSelect(['name', 'layout'])->addWhere('name', '=', $this->blocks[$node['#tag']]['name'])->execute()->first();
         }
         if (!empty($this->blocks[$node['#tag']]['layout'])) {
           $this->parseFields($this->blocks[$node['#tag']]['layout'], $entity, $join, $searchDisplay);
diff --git a/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php b/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php
new file mode 100644 (file)
index 0000000..44c2905
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Subscriber;
+
+use Civi\Afform\FormDataModel;
+use Civi\API\Events;
+use Civi\Api4\Afform;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Preprocess api autocomplete requests
+ */
+class AutocompleteSubscriber implements EventSubscriberInterface {
+
+  /**
+   * @return array
+   */
+  public static function getSubscribedEvents() {
+    return [
+      'civi.api.prepare' => ['onApiPrepare', Events::W_MIDDLE],
+    ];
+  }
+
+  /**
+   * @param \Civi\API\Event\PrepareEvent $event
+   *   API preparation event.
+   */
+  public function onApiPrepare(\Civi\API\Event\PrepareEvent $event) {
+    $apiRequest = $event->getApiRequest();
+    if (is_object($apiRequest) && is_a($apiRequest, 'Civi\Api4\Generic\AutocompleteAction')) {
+      $formName = $apiRequest->getFormName();
+      if (!$formName || !str_starts_with('afform:', $formName) || !strpos(':', $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')
+        ->setLayoutFormat('shallow')
+        ->execute()->first();
+      if (!$afform) {
+        return;
+      }
+      $formDataModel = new FormDataModel($afform['layout']);
+      $entity = $formDataModel->getEntity($entityName);
+      $field = $entity['fields'][$fieldName] ?? NULL;
+      if ($field) {
+        $apiRequest->setCheckPermissions(empty($field['defn']['bypass_permission']));
+        $apiRequest->setSavedSearch($field['defn']['saved_search'] ?? NULL);
+      }
+    }
+  }
+
+}
index a0b1100347e19a5012ae662ea58472b606f841f4..a7fc1e3787e4e60d536d8243fab82be2580fdc11 100644 (file)
@@ -56,6 +56,7 @@ function afform_civicrm_config(&$config) {
   $dispatcher->addListener('hook_civicrm_alterAngular', ['\Civi\Afform\AfformMetadataInjector', 'preprocess']);
   $dispatcher->addListener('hook_civicrm_check', ['\Civi\Afform\StatusChecks', 'hook_civicrm_check']);
   $dispatcher->addListener('civi.afform.get', ['\Civi\Api4\Action\Afform\Get', 'getCustomGroupBlocks']);
+  $dispatcher->addSubscriber(new \Civi\Api4\Subscriber\AutocompleteSubscriber());
 
   // Register support for email tokens
   if (CRM_Extension_System::singleton()->getMapper()->isActiveModule('authx')) {