Rework the listeners so that they are called on the basis of each entitiy rather...
authorSeamus Lee <seamuslee001@gmail.com>
Mon, 10 May 2021 09:26:39 +0000 (19:26 +1000)
committerSeamus Lee <seamuslee001@gmail.com>
Wed, 19 May 2021 09:26:02 +0000 (19:26 +1000)
ext/afform/core/CRM/Afform/Utils.php [new file with mode: 0644]
ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php
ext/afform/core/Civi/Api4/Action/Afform/Submit.php
ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php

diff --git a/ext/afform/core/CRM/Afform/Utils.php b/ext/afform/core/CRM/Afform/Utils.php
new file mode 100644 (file)
index 0000000..4b2d3ec
--- /dev/null
@@ -0,0 +1,52 @@
+<?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       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+class CRM_Afform_Utils {
+
+  public static function getEntityWeights($formEntities,  $entityValues) {
+    $entityWeights = $entityMapping = $entitiesToBeProcessed = [];
+    foreach ($formEntities as $entityName => $entity) {
+      $entityWeights[$entityName] = 1;
+      $entityMapping[$entityName] = $entity['type'];
+      foreach ($entityValues[$entity['type']][$entityName] as $index => $vals) {
+        foreach ($vals as $field => $value) {
+          if (array_key_exists($value, $entityWeights)) {
+            $entityWeights[$entityName] = max((int) $entityWeights[$entityName], (int) ($entityWeights[$value] + 1));
+          }
+          else {
+            if (!array_key_exists($value, $entitiesToBeProcessed)) {
+              $entitiesToBeProcessed[$value] = [$entityName];
+            }
+            else {
+              $entitiesToBeProcessed[$value][] = $entityName;
+            }
+          }
+        }
+      }
+      // If any other entities have been processed that relied on this entity lets now alter their weights based on this entity's weight.
+      if (array_key_exists($entityName, $entitiesToBeProcessed)) {
+        foreach ($entitiesToBeProcessed[$entityName] as $dependentEntity) {
+          $entityWeights[$dependentEntity] = max((int) $entityWeights[$dependentEntity], (int) ($entityWeights[$entityName] + 1));
+        }
+      }
+    }
+    // Numerically sort the weights now that we have them set
+    asort($entityWeights);
+    return $entityWeights;
+  }
+
+}
index f2bdf951aa6de02bc05be7697e20b325b4580676..c4f968c1b9b81f27c6c0ef2f7f8d6ef3de06c7a7 100644 (file)
@@ -20,17 +20,22 @@ class AfformSubmitEvent extends AfformBaseEvent {
 
   /**
    * @var array
-   *   List of definitions of the entities.
-   *   $entityDefns['spouse'] = ['type' => 'Individual'];
+   *   Values to be saved for this entity
+   *
    */
-  public $entityDefns;
+  public $values;
 
   /**
-   * @var array
-   *   List of submitted entities to save.
-   *   $entityValues['Contact']['spouse'] = ['first_name' => 'Optimus Prime'];
+   * @var string
+   *   entityType
+   */
+  public $entityType;
+
+  /**
+   * @var string
+   *   entityName e.g. Individual1, Activity1,
    */
-  public $entityValues;
+  public $entityName;
 
   /**
    * @var array
@@ -39,39 +44,23 @@ class AfformSubmitEvent extends AfformBaseEvent {
    */
   public $entityIds;
 
-  public $entityWeights;
-
-  public $entityMapping;
-
   /**
    * AfformSubmitEvent constructor.
    *
    * @param array $afform
    * @param \Civi\Afform\FormDataModel $formDataModel
    * @param \Civi\Api4\Action\Afform\Submit $apiRequest
-   * @param array $entityDefns
-   * @param array $entityValues
+   * @param array $values
+   * @param string $entityType
+   * @param string $entityName
    * @param array $entityIds
-   * @param array $entityWeights
-   * @param array $entityMapping
    */
-  public function __construct(array $afform, FormDataModel $formDataModel, Submit $apiRequest, $entityDefns, array $entityValues, array $entityIds, array $entityWeights, array $entityMapping) {
+  public function __construct(array $afform, FormDataModel $formDataModel, Submit $apiRequest, $values, string $entityType, string $entityName, array $entityIds) {
     parent::__construct($afform, $formDataModel, $apiRequest);
-    $this->entityDefns = $entityDefns;
-    $this->entityValues = $entityValues;
+    $this->values = $values;
+    $this->entityType = $entityType;
+    $this->entityName = $entityName;
     $this->entityIds = $entityIds;
-    $this->entityWeights = $entityWeights;
-    $this->entityMapping = $entityMapping;
-  }
-
-  /**
-   * List of entity types which need processing.
-   *
-   * @return array
-   *   Ex: ['Contact', 'Activity']
-   */
-  public function getTypes() {
-    return array_keys($this->entityValues);
   }
 
 }
index b79b807150b199f0170d786cd4da5d4fc5e429ae..ddfefa5917d3ff4dbd3be8682736021435916e69 100644 (file)
@@ -20,11 +20,9 @@ class Submit extends AbstractProcessor {
   protected $values;
 
   protected function processForm() {
-    $entityValues = $entityIds = $entityWeights = $entityMapping = [];
+    $entityValues = $entityIds = [];
     foreach ($this->_formDataModel->getEntities() as $entityName => $entity) {
       $entityIds[$entityName] = NULL;
-      $entityWeights[$entityName] = 1;
-      $entityMapping[$entityName] = $entity['type'];
       foreach ($this->values[$entityName] ?? [] as $values) {
         $entityValues[$entity['type']][$entityName][] = $values + ['fields' => []];
         // Predetermined values override submitted values
@@ -34,18 +32,13 @@ class Submit extends AbstractProcessor {
           }
         }
       }
-      foreach ($entityValues[$entity['type']][$entityName] as $index => $vals) {
-        foreach ($vals as $field => $value) {
-          if (in_array($value, array_keys($entityWeights))) {
-            $entityWeights[$entityName] = max((int) $entityWeights[$entityName], (int) ($entityWeights[$value] + 1));
-          }
-        }
-      }
     }
-    // Numerically sort the weights smallest to largest.
-    asort($entityWeights);
-    $event = new AfformSubmitEvent($this->_afform, $this->_formDataModel, $this, $this->_formDataModel->getEntities(), $entityValues, $entityIds, $entityWeights, $entityMapping);
-    \Civi::dispatcher()->dispatch(self::EVENT_NAME, $event);
+    $entityWeights = \CRM_Afform_Utils::getEntityWeights($this->_formDataModel->getEntities(), $entityValues);
+    foreach ($entityWeights as $entity => $weight) {
+      $values = $entityValues[$entityMapping[$entity]][$entity];
+      $event = new AfformSubmitEvent($this->_afform, $this->_formDataModel, $this, $values, $entityMapping[$entity], $entity, $entityIds);
+      \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))));
@@ -62,15 +55,14 @@ class Submit extends AbstractProcessor {
    * @see afform_civicrm_config
    */
   public static function processContacts(AfformSubmitEvent $event) {
-    foreach ($event->entityValues['Contact'] ?? [] as $entityName => $contacts) {
-      $api4 = $event->formDataModel->getSecureApi4($entityName);
-      foreach ($contacts as $contact) {
-        $saved = $api4('Contact', 'save', ['records' => [$contact['fields']]])->first();
-        $event->entityIds[$entityName] = $saved['id'];
-        self::saveJoins('Contact', $saved['id'], $contact['joins'] ?? []);
-      }
+    if ($event->entityType !== 'Contact') {
+      return;
     }
-    unset($event->entityValues['Contact']);
+    $entityName = $event->entityName;
+    $api4 = $event->formDataModel->getSecureApi4($entityName);
+    $saved = $api4('Contact', 'save', ['records' => [$event->values['fields']]])->first();
+    $event->entityIds[$entityName] = $saved['id'];
+    self::saveJoins('Contact', $saved['id'], $event->values['joins'] ?? []);
   }
 
   /**
@@ -79,22 +71,20 @@ class Submit extends AbstractProcessor {
    * @see afform_civicrm_config
    */
   public static function processGenericEntity(AfformSubmitEvent $event) {
-    foreach ($event->entityWeights as $entityName => $weight) {
-      $records = $event->entityValues[$event->entityMapping[$entityName]][$entityName];
-      $api4 = $event->formDataModel->getSecureApi4($entityName);
-      // Replace Entity reference fields that reference other form based entities with their created ids.
-      foreach ($records as $record) {
-        foreach ($record['fields'] as $field => $value) {
-          if (in_array($value, array_keys($event->entityIds)) && !empty($event->entityIds[$value])) {
-            $record['fields'][$field] = $event->entityIds[$value];
-          }
-        }
-        $saved = $api4($entityType, 'save', ['records' => [$record['fields']]])->first();
-        $event->entityIds[$entityName] = $saved['id'];
-        self::saveJoins($entityType, $saved['id'], $record['joins'] ?? []);
+    if ($event->entityType === 'Contact') {
+      return;
+    }
+    $entityName = $event->entityName;
+    $api4 = $event->formDataModel->getSecureApi4($event->entityName);
+    // Replace Entity reference fields that reference other form based entities with their created ids.
+    foreach ($record['fields'] as $field => $value) {
+      if (array_key_exists($value, $event->entityIds) && !empty($event->entityIds[$value])) {
+        $record['fields'][$field] = $event->entityIds[$value];
       }
     }
-    unset($event->entityValues[$entityType]);
+    $saved = $api4($entityType, 'save', ['records' => [$event->values['fields']]])->first();
+    $event->entityIds[$entityName] = $saved['id'];
+    self::saveJoins($entityType, $saved['id'], $event->values['joins'] ?? []);
   }
 
   protected static function saveJoins($mainEntityName, $entityId, $joins) {
index c759c16ee6a78008b05f3021e71c193f02a1d288..7715d9d0d805b26813873191b1ef081f98555fbb 100644 (file)
@@ -61,4 +61,65 @@ class CRM_Afform_UtilTest extends \PHPUnit\Framework\TestCase implements Headles
     $this->assertEquals($expected, $actual);
   }
 
+
+  public function formEntityWeightExampls() {
+    $exs = [];
+    $exs[] = [
+      [
+        'Individual1' => ['type' => 'Contact', ['fields' => ['first_name', 'last_name']]],
+        'Activity1' => ['type' => 'Activity', ['fields' => ['source_contact_id']]],
+      ],
+      [
+        'Contact' => ['Individual1' => ['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]],
+        'Activity' => ['Activity1' => ['fields' => ['source_contact_id' => 'Individual1']]],
+      ],
+      [
+        'Individual1' => 1,
+        'Activity1' => 2,
+      ],
+    ];
+    $exs[] = [
+      [
+        'Individual1' => ['type' => 'Contact', ['fields' => ['first_name', 'last_name']]],
+        'Event1' => ['type' => 'Event', ['fields' => ['created_id']]],
+        'LocBlock1' => ['type' => 'LocBlock', ['fields' => ['event_id']]],
+      ],
+      [
+        'Contact' => ['Individual1' => ['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]],
+        'Event' => ['Event1' => ['fields' => ['created_id' => 'Individual1']]],
+        'LocBlock' => ['LocBlock1' => ['fields' => ['event_id' => 'Event1']]],
+      ],
+      [
+        'Individual1' => 1,
+        'Event1' => 2,
+        'LocBlock1' => 3,
+      ],
+    ];
+    $exs[] = [
+      [
+        'Individual1' => ['type' => 'Contact', ['fields' => ['first_name', 'last_name']]],
+        'LocBlock1' => ['type' => 'LocBlock', ['fields' => ['event_id']]],
+        'Event1' => ['type' => 'Event', ['fields' => ['created_id']]],
+      ],
+      [
+        'Contact' => ['Individual1' => ['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]],
+        'LocBlock' => ['LocBlock1' => ['fields' => ['event_id' => 'Event1']]],
+        'Event' => ['Event1' => ['fields' => ['created_id' => 'Individual1']]],
+      ],
+      [
+        'Individual1' => 1,
+        'Event1' => 2,
+        'LocBlock1' => 3,
+      ],
+    ];
+    return $exs;
+  }
+
+  /**
+   * @dataProvider formEntityWeightExampls
+   */
+  public function testEntityWeights($formEntities, $entityValues, $expectedWeights) {
+    $this->assertEquals($expectedWeights, CRM_Afform_Utils::getEntityWeights($formEntities, $entityValues));
+  }
+
 }