PluginProbe
The Innovative Form Builder – IvyForms / 1.0
The Innovative Form Builder – IvyForms v1.0
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.0, at backend/src/Controllers/Form/FormSubmissionController.php

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