PluginProbe
The Innovative Form Builder – IvyForms / 0.8
The Innovative Form Builder – IvyForms v0.8
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 1.2 1.3
ivyforms / backend / src / Controllers / Form / FormSubmissionController.php

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

201 lines 7.2 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 // phpcs:disable PSR1.Files.SideEffects
11 if (!defined('ABSPATH')) {
12 exit; // Exit if accessed directly
13 }
14
15 use IvyForms\Common\Exceptions\ForbiddenException;
16 use IvyForms\Common\Exceptions\InvalidArgumentException;
17 use IvyForms\Common\Exceptions\NotFoundException;
18 use IvyForms\Common\Exceptions\ValidationException;
19 use IvyForms\Common\Helpers\EntryHelper;
20 use IvyForms\Common\Sanitizer\Sanitizer;
21 use IvyForms\Controllers\Controller;
22 use IvyForms\Factory\Entry\EntryFactory;
23 use IvyForms\Services\Confirmation\ConfirmationService;
24 use IvyForms\Services\Entry\EntryService;
25 use IvyForms\Services\Field\FieldService;
26 use IvyForms\Services\Field\FieldType;
27 use IvyForms\Services\Form\FormService;
28 use IvyForms\Services\Mailer\MailerService;
29 use IvyForms\Services\Notification\NotificationService;
30 use IvyForms\Services\Placeholder\PlaceholderService;
31 use IvyForms\Services\Security\SecurityService;
32 use IvyForms\Services\Translations\BackendStrings;
33 use WP_REST_Request;
34 use WP_REST_Response;
35
36 /**
37 * Class FormSubmissionController
38 *
39 * @package IvyForms\Controllers\Form
40 */
41 class FormSubmissionController extends Controller
42 {
43 private FormService $formService;
44 private FieldService $fieldService;
45 private NotificationService $notificationService;
46 private MailerService $mailerService;
47 private EntryService $entryService;
48 private SecurityService $securityService;
49 private ConfirmationService $confirmationService;
50
51 public function __construct(
52 FormService $formService,
53 FieldService $fieldService,
54 NotificationService $notificationService,
55 MailerService $mailerService,
56 EntryService $entryService,
57 SecurityService $securityService,
58 ConfirmationService $confirmationService
59 ) {
60 $this->formService = $formService;
61 $this->fieldService = $fieldService;
62 $this->notificationService = $notificationService;
63 $this->mailerService = $mailerService;
64 $this->entryService = $entryService;
65 $this->securityService = $securityService;
66 $this->confirmationService = $confirmationService;
67 }
68
69 /**
70 * @param WP_REST_Request $data
71 *
72 * @return WP_REST_Response
73 *
74 * @throws InvalidArgumentException|NotFoundException|ForbiddenException
75 * @throws ValidationException
76 */
77 public function handle(WP_REST_Request $data): WP_REST_Response
78 {
79 Sanitizer::verifyNonce($data->get_header('X-WP-Nonce'));
80
81 if (empty($data->get_params())) {
82 throw new InvalidArgumentException(
83 BackendStrings::getExceptionStrings()['invalid_request_data']
84 );
85 }
86
87 $formId = Sanitizer::sanitizeId($data->get_param('formId'));
88 Sanitizer::verifySubmissionNonce($data->get_param('nonce'), $formId);
89
90 if ($formId <= 0) {
91 throw new InvalidArgumentException(
92 BackendStrings::getExceptionStrings()['invalid_form_id']
93 );
94 }
95
96 $form = $this->formService->getFormById($formId);
97 $formFields = $this->fieldService->getAllFields($form->getId());
98
99 $this->fieldService->validateFieldsType($formFields);
100
101 // Build fieldLabels mapping for placeholders
102 $fieldLabels = PlaceholderService::buildFieldLabels($formFields);
103
104 // Validate CAPTCHA if present using SecurityService (automatically determines provider and validates)
105 $this->securityService->validateFormSubmission($data->get_params(), $formFields);
106
107 // Sanitize form submission data based on field types
108 $submissionData = Sanitizer::sanitizeFormSubmissionData($data->get_params(), $formFields);
109
110 [$isDuplicate, $duplicateErrors] = $this->fieldService->checkDuplicateFieldValues(
111 $formFields,
112 $submissionData,
113 $formId
114 );
115 if ($isDuplicate) {
116 return new WP_REST_Response([
117 'data' => [
118 'success' => null,
119 'entry' => ['stored' => false],
120 'confirmation' => null,
121 'is_duplicate' => true,
122 'duplicate_errors' => $duplicateErrors,
123 ],
124 ], 200);
125 }
126
127 $entryId = null;
128 $entry = [
129 'stored' => false
130 ];
131 /**
132 * Allow to hook before form submission for integrations
133 * @since 0.1.0
134 *
135 * Arguments:
136 * - int $formId The ID of the form being submitted
137 * - array $submissionData The form submission data (field values)
138 * - array $formFields The form field definitions
139 */
140 do_action('ivyforms/form/before_submission', $formId, $submissionData, $formFields);
141
142 if ($form->isStoreEntries()) {
143 $entryData = EntryHelper::buildEntryData($formId);
144 $entryObj = EntryFactory::create($entryData);
145 $entryId = $this->entryService->getEntryManager()->createEntry($entryObj);
146 $this->entryService->getEntryFieldManager()->addEntryFields($formFields, $entryId, $submissionData);
147 $entry = [
148 'stored' => true,
149 'id' => $entryId,
150 ];
151 }
152
153 // Build field and general entry data for placeholders
154 $fieldData = PlaceholderService::buildFieldData($formFields, $submissionData);
155 $generalData = PlaceholderService::buildGeneralData($entryId ?? 0, $submissionData);
156
157 // Use NotificationService for notifications
158 // Note: Notification messages are sanitized inside processNotifications() method
159 // to allow signature images with data: URIs (using Sanitizer::sanitizeHtmlContent)
160 $notificationsResult = $this->notificationService->processNotifications(
161 $formId,
162 $submissionData,
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