Skip to content

Commit

Permalink
Rework the listeners so that they are called on the basis of each ent…
Browse files Browse the repository at this point in the history
…itiy rather than just once. Also extract weight function out and make improvements following Coleman's review and add tests
  • Loading branch information
seamuslee001 committed May 10, 2021
1 parent 6a03450 commit 0ee3c91
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 66 deletions.
52 changes: 52 additions & 0 deletions ext/afform/core/CRM/Afform/Utils.php
Original file line number Diff line number Diff line change
@@ -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;
}

}
49 changes: 19 additions & 30 deletions ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

}
62 changes: 26 additions & 36 deletions ext/afform/core/Civi/Api4/Action/Afform/Submit.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -34,18 +32,13 @@ protected function processForm() {
}
}
}
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))));
Expand All @@ -62,15 +55,14 @@ protected function processForm() {
* @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($api4, '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($api4, 'Contact', $saved['id'], $event->values['joins'] ?? []);
}

/**
Expand All @@ -79,22 +71,20 @@ public static function processContacts(AfformSubmitEvent $event) {
* @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($api4, $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($api4, $entityType, $saved['id'], $event->values['joins'] ?? []);
}

protected static function saveJoins($api4, $mainEntityName, $entityId, $joins) {
Expand Down
61 changes: 61 additions & 0 deletions ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,65 @@ public function testNameConversion($inputFileName, $toFormat, $expected): void {
$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));
}

}

0 comments on commit 0ee3c91

Please sign in to comment.