Afform.submit - Use an event to allow the mix of prioritized special-case save methods
authorTim Otten <totten@civicrm.org>
Sat, 14 Sep 2019 01:59:06 +0000 (21:59 -0400)
committerCiviCRM <info@civicrm.org>
Wed, 16 Sep 2020 02:13:19 +0000 (19:13 -0700)
ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php [new file with mode: 0644]
ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php
ext/afform/core/Civi/Api4/Action/Afform/Submit.php
ext/afform/core/afform.php

diff --git a/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php b/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php
new file mode 100644 (file)
index 0000000..4eff408
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+namespace Civi\Afform\Event;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Class AfformSubmitEvent
+ * @package Civi\Afform\Event
+ *
+ * Handle submission of an "<af-form>".
+ * Listeners ought to take any recognized items from `entityValues`, handle
+ * them, and remove them.
+ *
+ * NOTE: I'm on the fence about whether to expose the arrays or more targeted
+ * methods. For the moment, this is only expected to be used internally,
+ * so KISS.
+ */
+class AfformSubmitEvent extends Event {
+
+  /**
+   * @var array
+   *   List of definitions of the entities.
+   *   $entityDefns['spouse'] = ['type' => 'Individual'];
+   */
+  public $entityDefns;
+
+  /**
+   * @var array
+   *   List of submitted entities to save.
+   *   $entityValues['Contact']['spouse'] = ['first_name' => 'Optimus Prime'];
+   */
+  public $entityValues;
+
+  /**
+   * AfformSubmitEvent constructor.
+   * @param $entityDefns
+   * @param array $entityValues
+   */
+  public function __construct($entityDefns, array $entityValues) {
+    $this->entityDefns = $entityDefns;
+    $this->entityValues = $entityValues;
+  }
+
+  /**
+   * List of entity types which need processing.
+   *
+   * @return array
+   *   Ex: ['Contact', 'Activity']
+   */
+  public function getTypes() {
+    return array_keys($this->entityValues);
+  }
+
+}
index 3c5085cbadc1b35f423916de126dbe54b4aa0546..a15074e320482fdcbc6cf324db694bd8e8b2bdc6 100644 (file)
@@ -25,7 +25,11 @@ abstract class AbstractProcessor extends \Civi\Api4\Generic\AbstractAction {
   protected $args;
 
   protected $_afform;
-  
+
+  /**
+   * @var array
+   *   List of entities declared by this form.
+   */
   protected $_afformEntities;
 
   public function _run(Result $result) {
index be9546c4717cf32d99c1b0337a49a17b5ead88aa..809b7ace6ccabe298e538f5260ebdac7ed04e6de 100644 (file)
@@ -2,12 +2,16 @@
 
 namespace Civi\Api4\Action\Afform;
 
+use Civi\Afform\Event\AfformSubmitEvent;
+
 /**
  * Class Submit
  * @package Civi\Api4\Action\Afform
  */
 class Submit extends AbstractProcessor {
 
+  const EVENT_NAME = 'civi.afform.submit';
+
   /**
    * Submitted values
    * @var array
@@ -15,40 +19,49 @@ class Submit extends AbstractProcessor {
    */
   protected $values;
 
-  /**
-   * @var array
-   */
-  protected $_submission = [];
-
   protected function processForm() {
+    $entityValues = [];
     foreach ($this->_afformEntities as $entityName => $entity) {
       // Predetermined values override submitted values
-      $this->_submission[$entity['type']][$entityName] = ($entity['af-values'] ?? []) + ($this->values[$entityName] ?? []);
+      $entityValues[$entity['type']][$entityName] = ($entity['af-values'] ?? []) + ($this->values[$entityName] ?? []);
     }
-    // Determines the order in which to process entities. Contacts go first.
-    $entitiesToProcess = [
-      'Contact' => 'processContacts',
-      'Activity' => 'processActivities',
-    ];
-    foreach ($entitiesToProcess as $entityType => $callback) {
-      if (!empty($this->_submission[$entityType])) {
-        $this->$callback($this->_submission[$entityType]);
-      }
-    }
-    foreach (array_diff_key($this->_submission, $entitiesToProcess) as $entityType) {
 
+    $event = new AfformSubmitEvent($this->_afformEntities, $entityValues);
+    \Civi::dispatcher()->dispatch(self::EVENT_NAME, $event);
+    foreach ($event->entityValues as $entityType => $entities) {
+      if (!empty($entities)) {
+        throw new \API_Exception(sprintf("Failed to process entities (type=%s; name=%s)", $entityType, implode(',', array_keys($entities))));
+      }
     }
-  }
 
-  protected function processGenericEntity($entityType, $items) {
-    foreach ($items as $name => $item) {
-      civicrm_api4($entityType, 'save', $items);
-    }
+    // What should I return?
+    return [];
   }
 
-  protected function processContacts($contacts) {
-    foreach ($contacts as $name => $contact) {
+  ///**
+  // * @param \Civi\Afform\Event\AfformSubmitEvent $event
+  // * @see afform_civicrm_config
+  // */
+  //public function processContacts(AfformSubmitEvent $event) {
+  //  if (empty($event->entityValues['Contact'])) {
+  //    return;
+  //  }
+  //  foreach ($event->entityValues['Contact'] as $entityName => $contact) {
+  //    // Do something
+  //    unset($event->entityValues['Contact'][$entityName]);
+  //  }
+  //}
 
+  /**
+   * @param \Civi\Afform\Event\AfformSubmitEvent $event
+   * @see afform_civicrm_config
+   */
+  public static function processGenericEntity(AfformSubmitEvent $event) {
+    foreach ($event->entityValues as $entityType => $records) {
+      civicrm_api4($entityType, 'save', [
+        'records' => $records,
+      ]);
+      unset($event->entityValues[$entityType]);
     }
   }
 
index 9ea9da18f69c6def3763fb33d29d968c60512a47..ba3f5c2ec5b87f83d8a116f06af87c7a832fc255 100644 (file)
@@ -2,6 +2,7 @@
 
 require_once 'afform.civix.php';
 use CRM_Afform_ExtensionUtil as E;
+use Civi\Api4\Action\Afform\Submit;
 
 function _afform_fields() {
   return ['name', 'title', 'description', 'requires', 'layout', 'server_route', 'client_route', 'is_public'];
@@ -49,6 +50,8 @@ function afform_civicrm_container($container) {
  */
 function afform_civicrm_config(&$config) {
   _afform_civix_civicrm_config($config);
+  // Civi::dispatcher()->addListener(Submit::EVENT_NAME, [Submit::class, 'processContacts'], -500);
+  Civi::dispatcher()->addListener(Submit::EVENT_NAME, [Submit::class, 'processGenericEntity'], -1000);
 }
 
 /**