PluginProbe
The Innovative Form Builder – IvyForms / 1.1
The Innovative Form Builder – IvyForms v1.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / backend / src / Controllers / Form / FormSubmissionController.php

FormSubmissionController.php in The Innovative Form Builder – IvyForms 1.1, at backend/src/Controllers/Form/FormSubmissionController.php

201 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @copyright © Melograno Venture Studio. All rights reserved.
5 * @licence See COPYING.md for license details.
6 */
7
8 namespace IvyForms\Controllers\Form;
9
10 use IvyForms\Common\Exceptions\ForbiddenException;
11 use IvyForms\Common\Exceptions\InvalidArgumentException;
12 use IvyForms\Common\Exceptions\NotFoundException;
13 use IvyForms\Common\Exceptions\ValidationException;
14 use IvyForms\Common\Helpers\EntryHelper;
15 use IvyForms\Common\Sanitizer\Sanitizer;
16 use IvyForms\Controllers\Controller;
17 use IvyForms\Factory\Entry\EntryFactory;
18 use IvyForms\Services\Confirmation\ConfirmationService;
19 use IvyForms\Services\Entry\EntryService;
20 use IvyForms\Services\Field\FieldDuplicateValidationService;
21 use IvyForms\Services\Field\FieldService;
22 use IvyForms\Services\Field\FieldType;
23 use IvyForms\Services\Form\FormService;
24 use IvyForms\Services\Mailer\MailerService;
25 use IvyForms\Services\Notification\NotificationService;
26 use IvyForms\Services\Placeholder\PlaceholderService;
27 use IvyForms\Services\Security\SecurityService;
28 use IvyForms\Services\Translations\BackendStrings;
29 use WP_REST_Request;
30 use WP_REST_Response;
31
32 /**
33 * Class FormSubmissionController
34 *
35 * @package IvyForms\Controllers\Form
36 */
37 class FormSubmissionController extends Controller
38 {
39 private FormService $formService;
40 private FieldService $fieldService;
41 private FieldDuplicateValidationService $fieldDuplicateValidationService;
42 private NotificationService $notificationService;
43 private MailerService $mailerService;
44 private EntryService $entryService;
45 private SecurityService $securityService;
46 private ConfirmationService $confirmationService;
47
48 public function __construct(
49 FormService $formService,
50 FieldService $fieldService,
51 FieldDuplicateValidationService $fieldDuplicateValidationService,
52 NotificationService $notificationService,
53 MailerService $mailerService,
54 EntryService $entryService,
55 SecurityService $securityService,
56 ConfirmationService $confirmationService
57 ) {
58 $this->formService = $formService;
59 $this->fieldService = $fieldService;
60 $this->fieldDuplicateValidationService = $fieldDuplicateValidationService;
61 $this->notificationService = $notificationService;
62 $this->mailerService = $mailerService;
63 $this->entryService = $entryService;
64 $this->securityService = $securityService;
65 $this->confirmationService = $confirmationService;
66 }
67
68 /**
69 * @param WP_REST_Request $data
70 *
71 * @return WP_REST_Response
72 *
73 * @throws InvalidArgumentException|NotFoundException|ForbiddenException
74 * @throws ValidationException
75 */
76 public function handle(WP_REST_Request $data): WP_REST_Response
77 {
78 Sanitizer::verifyNonce($data->get_header('X-WP-Nonce'));
79
80 if (empty($data->get_params())) {
81 throw new InvalidArgumentException(
82 BackendStrings::getExceptionStrings()['invalid_request_data']
83 );
84 }
85
86 $formId = Sanitizer::sanitizeId($data->get_param('formId'));
87 Sanitizer::verifySubmissionNonce($data->get_param('nonce'), $formId);
88
89 if ($formId <= 0) {
90 throw new InvalidArgumentException(
91 BackendStrings::getExceptionStrings()['invalid_form_id']
92 );
93 }
94
95 $form = $this->formService->getFormById($formId);
96 $formFields = $this->fieldService->getAllFields($form->getId());
97
98 $this->fieldService->validateFieldsType($formFields);
99
100 // Build fieldLabels mapping for placeholders
101 $fieldLabels = PlaceholderService::buildFieldLabels($formFields);
102
103 // Validate CAPTCHA if present using SecurityService (automatically determines provider and validates)
104 $this->securityService->validateFormSubmission($data->get_params(), $formFields);
105
106 // Sanitize form submission data based on field types
107 $submissionData = Sanitizer::sanitizeFormSubmissionData($data->get_params(), $formFields);
108
109 [$isDuplicate, $duplicateErrors] = $this->fieldDuplicateValidationService->checkDuplicateFieldValues(
110 $formFields,
111 $submissionData,
112 $formId
113 );
114 if ($isDuplicate) {
115 return new WP_REST_Response([
116 'data' => [
117 'success' => null,
118 'entry' => ['stored' => false],
119 'confirmation' => null,
120 'is_duplicate' => true,
121 'duplicate_errors' => $duplicateErrors,
122 ],
123 ], 200);
124 }
125
126 $entryId = null;
127 $entry = [
128 'stored' => false
129 ];
130 /**
131 * Allow to hook before form submission for integrations
132 * @since 0.1.0
133 *
134 * Arguments:
135 * - int $formId The ID of the form being submitted
136 * - array $submissionData The form submission data (field values)
137 * - array $formFields The form field definitions
138 */
139 do_action('ivyforms/form/before_submission', $formId, $submissionData, $formFields);
140
141 if ($form->isStoreEntries()) {
142 $entryData = EntryHelper::buildEntryData($formId);
143 $entryObj = EntryFactory::create($entryData);
144 $entryId = $this->entryService->getEntryManager()->createEntry($entryObj);
145 $this->entryService->getEntryFieldManager()->addEntryFields($formFields, $entryId, $submissionData);
146 $entry = [
147 'stored' => true,
148 'id' => $entryId,
149 ];
150 }
151
152 // Build field and general entry data for placeholders
153 $fieldData = PlaceholderService::buildFieldData($formFields, $submissionData);
154 $generalData = PlaceholderService::buildGeneralData($entryId ?? 0, $submissionData);
155
156 // Use NotificationService for notifications
157 // Note: Notification messages are sanitized inside processNotifications() method
158 // to allow signature images with data: URIs (using Sanitizer::sanitizeHtmlContent)
159 $notificationsResult = $this->notificationService->processNotifications(
160 $formId,
161 $submissionData,
162 $formFields,
163 $fieldData,
164 $generalData,
165 $this->mailerService,
166 $fieldLabels
167 );
168 // Use ConfirmationService for confirmations
169 $confirmationMessage = $this->confirmationService->processConfirmations(
170 $formId,
171 $fieldData,
172 $generalData,
173 $fieldLabels
174 );
175
176 // Sanitize confirmation message HTML to preserve colors and formatting
177 $safeConfirmationMessage = Sanitizer::sanitizeEditorContent($confirmationMessage);
178
179 /**
180 * Allow to hook after form submission for integrations
181 * @since 0.1.0
182 *
183 * Arguments:
184 * - int $formId The ID of the form being submitted
185 * - array $submissionData The form submission data (field values)
186 * - array $formFields The form field definitions
187 * - int|null $entryId The entry ID if entry storage is enabled
188 */
189 do_action('ivyforms/form/after_submission', $formId, $submissionData, $formFields, $entryId);
190
191 return new WP_REST_Response([
192 'message' => BackendStrings::getCommonStrings()['ok'],
193 'data' => [
194 'success' => $notificationsResult,
195 'entry' => $entry,
196 'confirmation' => $safeConfirmationMessage,
197 ],
198 ], 200);
199 }
200 }
201