From fb3888325736f2005668b4e69828da1c056a5430 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 13 Sep 2019 21:59:06 -0400 Subject: [PATCH] Afform.submit - Use an event to allow the mix of prioritized special-case save methods --- .../Civi/Afform/Event/AfformSubmitEvent.php | 54 ++++++++++++++++ .../Api4/Action/Afform/AbstractProcessor.php | 6 +- .../core/Civi/Api4/Action/Afform/Submit.php | 61 +++++++++++-------- ext/afform/core/afform.php | 3 + 4 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.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 index 0000000000..4eff408c40 --- /dev/null +++ b/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php @@ -0,0 +1,54 @@ +". + * 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); + } + +} diff --git a/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php b/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php index 3c5085cbad..a15074e320 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php @@ -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) { diff --git a/ext/afform/core/Civi/Api4/Action/Afform/Submit.php b/ext/afform/core/Civi/Api4/Action/Afform/Submit.php index be9546c471..809b7ace6c 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/Submit.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/Submit.php @@ -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]); } } diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index 9ea9da18f6..ba3f5c2ec5 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -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); } /** -- 2.25.1