3 namespace Civi\Api4\Action\Afform
;
5 use Civi\Afform\Event\AfformSubmitEvent
;
9 * @package Civi\Api4\Action\Afform
11 class Submit
extends AbstractProcessor
{
13 const EVENT_NAME
= 'civi.afform.submit';
22 protected function processForm() {
23 $entityValues = $entityIds = [];
24 foreach ($this->_formDataModel
->getEntities() as $entityName => $entity) {
25 $entityIds[$entityName] = NULL;
26 foreach ($this->values
[$entityName] ??
[] as $values) {
27 $entityValues[$entity['type']][$entityName][] = $values +
['fields' => []];
28 // Predetermined values override submitted values
29 if (!empty($entity['data'])) {
30 foreach ($entityValues[$entity['type']][$entityName] as $index => $vals) {
31 $entityValues[$entity['type']][$entityName][$index]['fields'] = $entity['data'] +
$vals['fields'];
36 $entityWeights = \CRM_Afform_Utils
::getEntityWeights($this->_formDataModel
->getEntities(), $entityValues);
37 foreach ($entityWeights as $entity => $weight) {
38 $values = $entityValues[$entityMapping[$entity]][$entity];
39 $event = new AfformSubmitEvent($this->_afform
, $this->_formDataModel
, $this, $values, $entityMapping[$entity], $entity, $entityIds);
40 \Civi
::dispatcher()->dispatch(self
::EVENT_NAME
, $event);
42 foreach ($event->entityValues
as $entityType => $entities) {
43 if (!empty($entities)) {
44 throw new \
API_Exception(sprintf("Failed to process entities (type=%s; name=%s)", $entityType, implode(',', array_keys($entities))));
48 // What should I return?
53 * @param \Civi\Afform\Event\AfformSubmitEvent $event
54 * @throws \API_Exception
55 * @see afform_civicrm_config
57 public static function processContacts(AfformSubmitEvent
$event) {
58 if ($event->entityType
!== 'Contact') {
61 $entityName = $event->entityName
;
62 $api4 = $event->formDataModel
->getSecureApi4($entityName);
63 $saved = $api4('Contact', 'save', ['records' => [$event->values
['fields']]])->first();
64 $event->entityIds
[$entityName] = $saved['id'];
65 self
::saveJoins('Contact', $saved['id'], $event->values
['joins'] ??
[]);
69 * @param \Civi\Afform\Event\AfformSubmitEvent $event
70 * @throws \API_Exception
71 * @see afform_civicrm_config
73 public static function processGenericEntity(AfformSubmitEvent
$event) {
74 if ($event->entityType
=== 'Contact') {
77 $entityName = $event->entityName
;
78 $api4 = $event->formDataModel
->getSecureApi4($event->entityName
);
79 // Replace Entity reference fields that reference other form based entities with their created ids.
80 foreach ($record['fields'] as $field => $value) {
81 if (array_key_exists($value, $event->entityIds
) && !empty($event->entityIds
[$value])) {
82 $record['fields'][$field] = $event->entityIds
[$value];
85 $saved = $api4($entityType, 'save', ['records' => [$event->values
['fields']]])->first();
86 $event->entityIds
[$entityName] = $saved['id'];
87 self
::saveJoins($entityType, $saved['id'], $event->values
['joins'] ??
[]);
90 protected static function saveJoins($mainEntityName, $entityId, $joins) {
91 foreach ($joins as $joinEntityName => $join) {
92 $values = self
::filterEmptyJoins($joinEntityName, $join);
93 // TODO: REPLACE works for creating or updating contacts, but different logic would be needed if
94 // the contact was being auto-updated via a dedupe rule; in that case we would not want to
95 // delete any existing records.
97 civicrm_api4($joinEntityName, 'replace', [
98 // Disable permission checks because the main entity has already been vetted
99 'checkPermissions' => FALSE,
100 'where' => self
::getJoinWhereClause($mainEntityName, $joinEntityName, $entityId),
101 'records' => $values,
104 // REPLACE doesn't work if there are no records, have to use DELETE
107 civicrm_api4($joinEntityName, 'delete', [
108 // Disable permission checks because the main entity has already been vetted
109 'checkPermissions' => FALSE,
110 'where' => self
::getJoinWhereClause($mainEntityName, $joinEntityName, $entityId),
113 catch (\API_Exception
$e) {
114 // No records to delete
121 * Filter out joins that have been left blank on the form
127 private static function filterEmptyJoins($entity, $join) {
128 return array_filter($join, function($item) use($entity) {
131 return !empty($item['email']);
134 return !empty($item['phone']);
137 return !empty($item['name']);
140 return !empty($item['url']);
143 \CRM_Utils_Array
::remove($item, 'id', 'is_primary', 'location_type_id', 'entity_id', 'contact_id', 'entity_table');
144 return (bool) array_filter($item);