PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Submission / SubmissionService.php

SubmissionService.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.14, at app/Services/Submission/SubmissionService.php

840 lines 29.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\Submission;
4
5 defined('ABSPATH') or die;
6
7 use Exception;
8 use FluentForm\App\Models\EntryDetails;
9 use FluentForm\App\Models\Form;
10 use FluentForm\App\Helpers\Helper;
11 use FluentForm\App\Models\FormMeta;
12 use FluentForm\App\Models\Submission;
13 use FluentForm\Framework\Support\Arr;
14 use FluentForm\App\Models\SubmissionMeta;
15 use FluentForm\Framework\Support\Collection;
16 use FluentForm\App\Services\Form\FormService;
17 use FluentForm\App\Modules\Form\FormDataParser;
18 use FluentForm\App\Modules\Form\FormFieldsParser;
19 use FluentForm\App\Services\Manager\FormManagerService;
20
21 class SubmissionService
22 {
23 /**
24 * @var \FluentForm\App\Models\Submission|\FluentForm\Framework\Database\Query\Builder|\FluentForm\Framework\Database\Orm\Builder
25 */
26 protected $model;
27 protected $formService;
28
29 public function __construct()
30 {
31 $this->model = new Submission();
32 $this->formService = new FormService();
33 }
34
35 public function get($attributes = [])
36 {
37 if (!defined('FLUENTFORM_RENDERING_ENTRIES')) {
38 define('FLUENTFORM_RENDERING_ENTRIES', true);
39 }
40
41 $entries = $this->model->paginateEntries($attributes);
42
43 if (Arr::get($attributes, 'parse_entry')) {
44 $form = Form::find(Arr::get($attributes, 'form_id'));
45
46 $parsedEntries = FormDataParser::parseFormEntries($entries->items(), $form);
47
48 $entries->setCollection(Collection::make($parsedEntries));
49 }
50
51 return apply_filters('fluentform/get_submissions', $entries);
52 }
53
54 public function find($submissionId)
55 {
56 try {
57 if (!defined('FLUENTFORM_RENDERING_ENTRY')) {
58 define('FLUENTFORM_RENDERING_ENTRY', true);
59 }
60
61 $submission = $this->model->with(['form','submissionMeta' => function($q) {
62 $q->where('meta_key', '_entry_uid_hash');
63 }])->findOrFail($submissionId);
64
65 $form = $submission->form;
66
67
68 $autoRead = apply_filters_deprecated(
69 'fluentform_auto_read',
70 [true, $form],
71 FLUENTFORM_FRAMEWORK_UPGRADE,
72 'fluentform/auto_read_submission'
73 );
74
75 $autoRead = apply_filters('fluentform/auto_read_submission', $autoRead, $form);
76
77 if ('unread' === $submission->status && $autoRead) {
78 $submission->fill(['status' => 'read'])->save();
79 }
80
81 $meta = $submission->submissionMeta;
82 if (count($meta)) {
83 $submission->_entry_uid_hash = Arr::get($meta, '0.value');
84 $this->setEntryUidLink($submission);
85 }
86
87 $submission = apply_filters('fluentform/submission_before_parse', $submission, $form);
88
89 $submission = FormDataParser::parseFormEntry($submission, $form, null, true);
90 $this->enrichWithUser($submission);
91
92 $submission = apply_filters_deprecated(
93 'fluentform_single_response_data',
94 [$submission, $form->id],
95 FLUENTFORM_FRAMEWORK_UPGRADE,
96 'fluentform/find_submission'
97 );
98
99 return apply_filters('fluentform/find_submission', $submission, $form->id)->makeHidden('form');
100 } catch (Exception $e) {
101 throw new Exception(
102 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
103 __('No Entry found.', 'fluentform')
104 );
105 }
106 }
107
108
109 /**
110 * @param array{
111 * formId?: int, // Optional when using uidHash
112 * serialNumber?: int, // Required if using formId without uidHash
113 * uidHash?: string, // Can be used with or without formId
114 * isHtml?: bool
115 * } $params Either (formId + serialNumber) OR uidHash required
116 *
117 * @return Submission
118 * @throws Exception
119 */
120 public function findByParams($params)
121 {
122 try {
123 if (!defined('FLUENTFORM_RENDERING_ENTRY')) {
124 define('FLUENTFORM_RENDERING_ENTRY', true);
125 }
126
127 $formId = $params['formId'] ?? null;
128 $serialNumber = $params['serialNumber'] ?? null;
129 $uidHash = $params['uidHash'] ?? null;
130 $isHtml = $params['isHtml'] ?? false;
131 if (!($uidHash || ($formId && $serialNumber))) {
132 throw new \Exception(
133 __('Either uidHash or (formId + serialNumber) must be provided', 'fluentform')
134 );
135 }
136
137 $query = Submission::query();
138
139 if ($formId) {
140 $query->where('form_id', $formId);
141 }
142
143 if ($serialNumber) {
144 $query->where('serial_number', $serialNumber);
145 } else {
146 $query->whereHas('submissionMeta', function ($metaQuery) use ($uidHash) {
147 $metaQuery->where('meta_key', '_entry_uid_hash')
148 ->where('value', $uidHash); // Changed to 'value' column
149 });
150 }
151
152 $submission = $query->orderBy('serial_number', 'desc')->first();
153
154 if (!$submission) {
155 throw new \Exception(
156 __('No entry found matching the criteria', 'fluentform')
157 );
158 }
159 $form = $submission->form;
160
161 $autoRead = apply_filters('fluentform/auto_read_submission', true, $form);
162
163 if ('unread' === $submission->status && $autoRead) {
164 $submission->fill(['status' => 'read'])->save();
165 }
166
167 $meta = $submission->submissionMeta()->where('meta_key', '_entry_uid_hash')->first();
168 if ($meta && $meta->value) {
169 $submission->_entry_uid_hash = $meta->value;
170 $this->setEntryUidLink($submission);
171 }
172
173 $submission = FormDataParser::parseFormEntry($submission, $form, null, $isHtml);
174 $this->enrichWithUser($submission);
175
176 return apply_filters('fluentform/find_submission', $submission, $form->id);
177 } catch (Exception $e) {
178 throw new Exception(
179 sprintf(
180 /* translators: %s: error message */
181 esc_html__('No Entry found. Error: %s', 'fluentform'),
182 esc_html($e->getMessage())
183 )
184 );
185 }
186 }
187
188 public function resources($attributes)
189 {
190 $resources = [];
191
192 $formId = Arr::get($attributes, 'form_id');
193 $submissionId = Arr::get($attributes, 'entry_id');
194
195 // When an entry is targeted, the authoritative form is the one stored on
196 // that submission — never a separately supplied request form_id, which
197 // could point counts/labels/fields/metadata reads at another form the
198 // caller was not authorized for (authorization resolved from the entry).
199 if ($submissionId) {
200 $submission = $this->model->find($submissionId);
201 if ($submission) {
202 $formId = (int) $submission->form_id;
203 }
204 }
205
206 if (Arr::get($attributes, 'counts')) {
207 $resources['counts'] = $this->model->countByGroup($formId);
208 }
209
210 $formInputsAndLabels = null;
211
212 $wantsLabels = Arr::get($attributes, 'labels');
213
214 if ($wantsLabels) {
215 $formInputsAndLabels = $this->formService->getInputsAndLabels($formId);
216 $resources['labels'] = $formInputsAndLabels['labels'];
217 }
218
219 if (Arr::get($attributes, 'fields')) {
220 $formInputsAndLabels = $formInputsAndLabels ? $formInputsAndLabels : $this->formService->getInputsAndLabels($formId);
221 $resources['fields'] = $formInputsAndLabels['inputs'];
222 }
223
224 if (Arr::get($attributes, 'visibleColumns')) {
225 $resources['visibleColumns'] = Helper::getFormMeta($formId, '_visible_columns', null);
226 }
227
228 if (Arr::get($attributes, 'columnsOrder')) {
229 $resources['columnsOrder'] = Helper::getFormMeta($formId, '_columns_order', null);
230 }
231
232 if (Arr::get($attributes, 'next')) {
233 $resources['next'] = $this->model->findAdjacentSubmission($attributes);
234 }
235
236 if (Arr::get($attributes, 'previous')) {
237 $attributes['direction'] = 'previous';
238 $resources['previous'] = $this->model->findAdjacentSubmission($attributes);
239 }
240 if (count(array_intersect(['orderData', 'widgets', 'cards'], array_keys($attributes))) > 0) {
241 try {
242 $submission = $this->model->with('form')->findOrFail($submissionId);
243 } catch (Exception $e) {
244 throw new Exception(
245 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
246 __('No Entry found.', 'fluentform')
247 );
248 }
249
250 if (Arr::get($attributes, 'orderData')) {
251 $hasPayment = $submission->payment_status || $submission->payment_total || 'subscription' === $submission->payment_type;
252
253 if ($hasPayment) {
254 $resources['orderData'] = apply_filters(
255 'fluentform/submission_order_data',
256 false,
257 $submission,
258 $submission->form
259 );
260
261 if ($wantsLabels) {
262 $resources['labels'] = apply_filters(
263 'fluentform/submission_labels',
264 $resources['labels'],
265 $submission,
266 $submission->form
267 );
268 }
269 }
270 }
271
272 if (Arr::get($attributes, 'widgets')) {
273 $resources['widgets'] = apply_filters(
274 'fluentform/submissions_widgets', [], $resources, $submission
275 );
276 }
277
278 if (Arr::get($attributes, 'cards')) {
279 $resources['cards'] = apply_filters(
280 'fluentform/submission_cards', [], $resources, $submission
281 );
282 }
283 }
284
285 return apply_filters('fluentform/submission_resources', $resources);
286 }
287
288 public function updateStatus($attributes = [])
289 {
290 $submissionId = intval(Arr::get($attributes, 'entry_id'));
291
292 $status = sanitize_text_field(Arr::get($attributes, 'status'));
293
294 $submission = $this->model->find($submissionId);
295
296 if (!$submission) {
297 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
298 throw new Exception(__('Submission not found', 'fluentform'));
299 }
300
301 if (!isset(Helper::getMutableEntryStatuses($submission->form_id, $submissionId)[$status])) {
302 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
303 throw new Exception(__('Invalid entry status', 'fluentform'));
304 }
305
306 $this->model->amend($submissionId, ['status' => $status]);
307
308 do_action('fluentform/after_submission_status_update', $submissionId, $status);
309
310 return $status;
311 }
312
313 public function toggleIsFavorite($submissionId)
314 {
315 try {
316 $submission = $this->model->findOrFail($submissionId);
317 } catch (Exception $e) {
318 throw new Exception(
319 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
320 __('No Entry found.', 'fluentform')
321 );
322 }
323
324 if ($submission->is_favourite) {
325 $message = __('The entry has been removed from favorites', 'fluentform');
326 } else {
327 $message = __('The entry has been marked as favorites', 'fluentform');
328 }
329
330 $submission->fill(['is_favourite' => !$submission->is_favourite])->save();
331
332 return [$message, $submission->is_favourite];
333 }
334
335 public function storeColumnSettings($attributes = [])
336 {
337 $formId = intval(Arr::get($attributes, 'form_id'));
338 $metaKey = sanitize_text_field(Arr::get($attributes, 'meta_key'));
339
340 $allowedKeys = ['_visible_columns', '_columns_order'];
341 if (!in_array($metaKey, $allowedKeys)) {
342 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
343 throw new \Exception(__('Invalid meta key for column settings.', 'fluentform'));
344 }
345
346 $metaValue = wp_unslash(Arr::get($attributes, 'settings'));
347
348 FormMeta::persist($formId, $metaKey, $metaValue);
349 }
350
351 public function handleBulkActions($attributes = [])
352 {
353 $formId = intval(Arr::get($attributes, 'form_id'));
354
355 $submissionIds = fluentFormSanitizer(Arr::get($attributes, 'entries', []));
356
357 $actionType = sanitize_text_field(Arr::get($attributes, 'action_type'));
358
359 if (!$formId || !count($submissionIds)) {
360 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
361 throw new Exception(__('Please select entries first', 'fluentform'));
362 }
363
364 // Re-verify against the form actually mutated; the policy scopes on a request entry_id.
365 if (!FormManagerService::hasFormPermission($formId)) {
366 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
367 throw new Exception(__('You do not have permission to modify this form\'s entries.', 'fluentform'));
368 }
369
370 $query = $this->model->where('form_id', $formId)->whereIn('id', $submissionIds);
371
372 $statuses = Helper::getMutableEntryStatuses($formId);
373
374 $message = '';
375
376 if (isset($statuses[$actionType])) {
377 // Hook only ids this form owns; array_flip keeps the caller's own id values and order.
378 $ownedIds = array_flip(
379 $this->model->where('form_id', $formId)->whereIn('id', $submissionIds)->pluck('id')->all()
380 );
381
382 $query->update([
383 'status' => $actionType,
384 'updated_at' => current_time('mysql'),
385 ]);
386
387 foreach ($submissionIds as $submissionId) {
388 if (isset($ownedIds[$submissionId])) {
389 do_action('fluentform/after_submission_status_update', $submissionId, $actionType);
390 }
391 }
392
393 $message = 'Selected entries successfully marked as ' . $statuses[$actionType];
394 } elseif ('other.delete_permanently' == $actionType) {
395 $ownedIds = $this->model->where('form_id', $formId)
396 ->whereIn('id', $submissionIds)
397 ->pluck('id')
398 ->all();
399
400 if ($ownedIds) {
401 $this->deleteEntries($ownedIds, $formId);
402 }
403
404 $message = __('Selected entries successfully deleted', 'fluentform');
405 } elseif ('other.make_favorite' == $actionType) {
406 $query->update([
407 'is_favourite' => 1,
408 ]);
409
410 $message = __('Selected entries successfully marked as favorites', 'fluentform');
411 } elseif ('other.unmark_favorite' == $actionType) {
412 $query->update([
413 'is_favourite' => 0,
414 ]);
415
416 $message = __('Selected entries successfully removed from favorites', 'fluentform');
417 }
418
419 return $message;
420 }
421
422 public function deleteEntries($submissionIds, $formId)
423 {
424 $submissionIds = (array)$submissionIds;
425
426 do_action('fluentform/before_deleting_entries', $submissionIds, $formId);
427
428 foreach ($submissionIds as $submissionId) {
429 do_action_deprecated(
430 'fluentform_before_entry_deleted',
431 [$submissionId, $formId],
432 FLUENTFORM_FRAMEWORK_UPGRADE,
433 'fluentform/before_deleting_entries'
434 );
435 }
436
437 $this->deleteFiles($submissionIds, $formId);
438
439 Submission::remove($submissionIds, $formId);
440
441 do_action('fluentform/after_deleting_submissions', $submissionIds, $formId);
442
443 foreach ($submissionIds as $submissionId) {
444 do_action_deprecated(
445 'fluentform_after_entry_deleted',
446 [$submissionId, $formId],
447 FLUENTFORM_FRAMEWORK_UPGRADE,
448 'fluentform/after_deleting_entries'
449 );
450 }
451 }
452
453 public function deleteFiles($submissionIds, $formId)
454 {
455 apply_filters_deprecated(
456 'fluentform_disable_attachment_delete',
457 [
458 false,
459 $formId
460 ],
461 FLUENTFORM_FRAMEWORK_UPGRADE,
462 'fluentform/disable_attachment_delete',
463 'Use fluentform/disable_attachment_delete instead of fluentform_disable_attachment_delete'
464 );
465
466 $disableAttachmentDelete = apply_filters(
467 'fluentform/disable_attachment_delete', false, $formId
468 );
469
470 $shouldDelete = defined('FLUENTFORMPRO') && $formId && !$disableAttachmentDelete;
471
472 if ($shouldDelete) {
473 $deletables = $this->getAttachments($submissionIds, $formId);
474
475 foreach ($deletables as $file) {
476 $fileName = basename($file);
477
478 // Plugin uploads are ff-prefixed, so guard files and dot-files can only be crafted.
479 if ('' === $fileName || '.' === $fileName[0]
480 || in_array(strtolower($fileName), ['index.php', 'web.config'], true)) {
481 continue;
482 }
483
484 $file = wp_upload_dir()['basedir'] . FLUENTFORM_UPLOAD_DIR . '/' . $fileName;
485
486 if (is_readable($file) && !is_dir($file)) {
487 wp_delete_file($file);
488 }
489 }
490 // Empty Temp Uploads
491 if (defined('FLUENTFORMPRO')) {
492 $tempDir = wp_upload_dir()['basedir'] . FLUENTFORM_UPLOAD_DIR . '/temp/';
493 $files = glob($tempDir . '*');
494 if(!empty($files)){
495 // Shared across forms/visitors: only aged files, never an in-flight upload.
496 $cutoff = time() - apply_filters('fluentform/temp_file_delete_time', 172800);
497 foreach ($files as $file) {
498 if (basename($file) !== 'index.php' && is_file($file) && filemtime($file) < $cutoff) {
499 wp_delete_file($file);
500 }
501 }
502 }
503 }
504
505 }
506 }
507
508 public function getAttachments($submissionIds, $form)
509 {
510 $submissionIds = (array)$submissionIds;
511
512 if (!$form instanceof Form) {
513 $form = Form::find($form);
514 }
515
516 $fields = FormFieldsParser::getAttachmentInputFields($form, ['element', 'attributes']);
517
518 $attachments = [];
519
520 if ($fields) {
521 $fields = Arr::pluck($fields, 'attributes.name');
522
523 $submissions = $this->model->whereIn('id', $submissionIds)->get();
524
525 foreach ($submissions as $submission) {
526 $response = json_decode($submission->response, true);
527
528 $files = Arr::collapse(Arr::only($response, $fields));
529
530 $attachments = array_merge($attachments, $files);
531 }
532 }
533
534 return $attachments;
535 }
536
537 public function getNotes($submissionId, $attributes)
538 {
539 $formId = (int)Arr::get($attributes, 'form_id');
540 $apiLog = 'yes' === sanitize_text_field(Arr::get($attributes, 'api_log'));
541
542 $metaKeys = ['_notes'];
543
544 if ($apiLog) {
545 $metaKeys[] = 'api_log';
546 }
547
548 $perPage = (int) Arr::get($attributes, 'per_page', 0);
549 $page = (int) Arr::get($attributes, 'page', 1);
550
551 $query = SubmissionMeta::where('response_id', $submissionId)
552 ->whereIn('meta_key', $metaKeys)
553 ->orderBy('id', 'DESC');
554
555 if ($perPage > 0) {
556 $perPage = min($perPage, 100);
557 $notes = $query->forPage($page, $perPage)->get();
558 } else {
559 $notes = $query->get();
560 }
561
562 // Batch-fetch users to avoid N+1 queries
563 $userIds = $notes->pluck('user_id')->filter()->unique()->values()->toArray();
564 $usersMap = [];
565 if (!empty($userIds)) {
566 $users = get_users(['include' => $userIds, 'fields' => ['ID', 'display_name']]);
567 foreach ($users as $user) {
568 $usersMap[$user->ID] = $user->display_name;
569 }
570 }
571
572 foreach ($notes as $note) {
573 if ($note->user_id) {
574 $note->pemalink = get_edit_user_link($note->user_id);
575 if (isset($usersMap[$note->user_id])) {
576 $note->created_by = $usersMap[$note->user_id];
577 } else {
578 $note->created_by = __('Fluent Forms Bot', 'fluentform');
579 }
580 } else {
581 $note->pemalink = false;
582 }
583 }
584
585 apply_filters_deprecated(
586 'fluentform_entry_notes',
587 [
588 $notes,
589 $submissionId,
590 $formId
591 ],
592 FLUENTFORM_FRAMEWORK_UPGRADE,
593 'fluentform/entry_notes',
594 'Use fluentform/entry_notes instead of fluentform_entry_notes'
595 );
596
597 $notes = apply_filters('fluentform/entry_notes', $notes, $submissionId, $formId);
598
599 return apply_filters('fluentform/submission_notes', $notes, $submissionId, $formId);
600 }
601
602 public function storeNote($submissionId, $attributes = [])
603 {
604 // SECURITY (FINDING-20): derive form_id from the route-authorized submission, not the
605 // request body. Authorization is computed from the entry_id, but the note row's form_id
606 // came straight from the body — letting a manager scoped to one form write a note row into
607 // another form's meta namespace (cross-form integrity pollution).
608 $submission = Submission::find($submissionId);
609 $formId = $submission ? intval($submission->form_id) : intval(Arr::get($attributes, 'form_id'));
610
611 $content = sanitize_textarea_field($attributes['note']['content']);
612 $status = sanitize_text_field($attributes['note']['status']);
613 $user = get_user_by('ID', get_current_user_id());
614 $now = current_time('mysql');
615
616 $note = [
617 'response_id' => $submissionId,
618 'form_id' => $formId,
619 'meta_key' => '_notes',
620 'value' => $content,
621 'status' => $status,
622 'user_id' => $user->ID,
623 'name' => $user->display_name,
624 'created_at' => $now,
625 'updated_at' => $now,
626 ];
627
628 $note = apply_filters_deprecated(
629 'fluentform_add_response_note',
630 [$note],
631 FLUENTFORM_FRAMEWORK_UPGRADE,
632 'fluentform/store_submission_note'
633 );
634
635 $note = apply_filters('fluentform/store_submission_note', $note);
636
637 $submissionMeta = new SubmissionMeta;
638
639 $submissionMeta->fill($note)->save();
640
641 do_action_deprecated(
642 'fluentform_new_response_note_added',
643 [$submissionMeta->id, $submissionMeta],
644 FLUENTFORM_FRAMEWORK_UPGRADE,
645 'fluentform/submission_note_stored'
646 );
647
648 do_action('fluentform/submission_note_stored', $submissionMeta->id, $submissionMeta);
649
650 return [
651 'message' => __('Note has been successfully added', 'fluentform'),
652 'note' => $submissionMeta,
653 'insert_id' => $submissionMeta->id,
654 ];
655 }
656
657 public function updateSubmissionUser($userId, $submissionId)
658 {
659 if (!$userId || !$submissionId) {
660 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
661 throw new Exception(__('Submission ID and User ID is required', 'fluentform'));
662 }
663
664 $submission = Submission::find($submissionId);
665 $user = get_user_by('ID', $userId);
666
667 if (!$submission || $submission->user_id == $userId || !$user) {
668 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
669 throw new Exception(__('Invalid Request', 'fluentform'));
670 }
671
672 Submission::where('id', $submission->id)
673 ->update([
674 'user_id' => $userId,
675 'updated_at' => current_time('mysql'),
676 ]);
677
678 if (defined('FLUENTFORMPRO')) {
679 // let's update the corresponding user IDs for transactions
680 \FluentForm\App\Models\Transaction::where('submission_id', $submission->id)
681 ->update([
682 'user_id' => $userId,
683 'updated_at' => current_time('mysql'),
684 ]);
685 }
686
687 do_action('fluentform/log_data', [
688 'parent_source_id' => $submission->form_id,
689 'source_type' => 'submission_item',
690 'source_id' => $submission->id,
691 'component' => 'General',
692 'status' => 'info',
693 'title' => 'Associate user has been changed from ' . $submission->user_id . ' to ' . $userId,
694 ]);
695
696 do_action_deprecated(
697 'fluentform_submission_user_changed',
698 [
699 $submission,
700 $user
701 ],
702 FLUENTFORM_FRAMEWORK_UPGRADE,
703 'fluentform/submission_user_changed',
704 'Use fluentform/submission_user_changed instead of fluentform_submission_user_changed.'
705 );
706
707 do_action('fluentform/submission_user_changed', $submission, $user);
708
709 return ([
710 'message' => __('Selected user has been successfully assigned to this submission', 'fluentform'),
711 'user' => [
712 'name' => $user->display_name,
713 'email' => $user->user_email,
714 'ID' => $user->ID,
715 'permalink' => get_edit_user_link($user->ID),
716 ],
717 'user_id' => $userId,
718 ]);
719 }
720
721 public function updateEntryDiffs($entryId, $formId, $formData)
722 {
723 EntryDetails::where('submission_id', $entryId)
724 ->where('form_id', $formId)
725 ->whereIn('field_name', array_keys($formData))
726 ->delete();
727
728 $entryItems = [];
729 foreach ($formData as $dataKey => $dataValue) {
730 if (!$dataValue) {
731 continue;
732 }
733
734 if (is_array($dataValue)) {
735 foreach ($dataValue as $subKey => $subValue) {
736 $entryItems[] = [
737 'form_id' => $formId,
738 'submission_id' => $entryId,
739 'field_name' => $dataKey,
740 'sub_field_name' => $subKey,
741 'field_value' => maybe_serialize($subValue),
742 ];
743 }
744 } else {
745 $entryItems[] = [
746 'form_id' => $formId,
747 'submission_id' => $entryId,
748 'field_name' => $dataKey,
749 'sub_field_name' => '',
750 'field_value' => $dataValue,
751 ];
752 }
753 }
754
755 if ($entryItems) {
756 EntryDetails::insert($entryItems);
757 }
758
759 return true;
760 }
761
762 public function recordEntryDetails($entryId, $formId, $data)
763 {
764 $formData = Arr::except($data, Helper::getWhiteListedFields($formId));
765
766 $entryItems = [];
767 foreach ($formData as $dataKey => $dataValue) {
768 if ($dataValue === '' || $dataValue === null) {
769 continue;
770 }
771
772 if (is_array($dataValue) || is_object($dataValue)) {
773 foreach ($dataValue as $subKey => $subValue) {
774 if (empty($subValue)) {
775 continue;
776 }
777 $entryItems[] = [
778 'form_id' => $formId,
779 'submission_id' => $entryId,
780 'field_name' => trim($dataKey),
781 'sub_field_name' => $subKey,
782 'field_value' => maybe_serialize($subValue),
783 ];
784 }
785 } else {
786 $entryItems[] = [
787 'form_id' => $formId,
788 'submission_id' => $entryId,
789 'field_name' => trim($dataKey),
790 'sub_field_name' => '',
791 'field_value' => $dataValue,
792 ];
793 }
794 }
795
796 if ($entryItems) {
797 EntryDetails::insert($entryItems);
798 }
799
800 return true;
801 }
802
803 public function getPrintContent($attr)
804 {
805 $content = (new SubmissionPrint())->getContent($attr);
806 return array('success' => true, 'content' => $content);
807 }
808
809 private function setEntryUidLink($submission)
810 {
811 $frontEndSettings = Helper::getFormMeta($submission->form_id, 'front_end_entry_view', []);
812 if (Arr::get($frontEndSettings, 'status') === 'yes') {
813 $submission->entry_uid_link = site_url('?ff_entry=1&hash=' . $submission->_entry_uid_hash);
814 }
815 }
816
817 private function enrichWithUser($submission)
818 {
819 if (!$submission->user_id) {
820 return;
821 }
822
823 $user = get_user_by('ID', $submission->user_id);
824 if (!$user) {
825 return;
826 }
827
828 $userDisplayName = trim($user->first_name . ' ' . $user->last_name);
829 if (!$userDisplayName) {
830 $userDisplayName = $user->display_name;
831 }
832
833 $submission->user = [
834 'ID' => $user->ID,
835 'name' => $userDisplayName,
836 'permalink' => get_edit_user_link($user->ID),
837 ];
838 }
839 }
840