PluginProbe
The Innovative Form Builder – IvyForms / 1.5
The Innovative Form Builder – IvyForms v1.5
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
← All changes | backend/src/Services/Entry/Managers/EntryFieldManager.php +206 -0 0.6.1 → 1.5 View file →
@@ -1,0 +1,206 @@
1 +<?php
2 +
3 +namespace IvyForms\Services\Entry\Managers;
4 +
5 +use IvyForms\Common\Exceptions\ValidationException;
6 +use IvyForms\Common\Helpers\EntryHelper;
7 +use IvyForms\Common\Helpers\FieldHelper;
8 +use IvyForms\Entity\EntryField\EntryField;
9 +use IvyForms\Factory\EntryField\EntryFieldFactory;
10 +use IvyForms\Repository\Entry\EntryRepositoryInterface;
11 +use IvyForms\Repository\EntryField\EntryFieldRepositoryInterface;
12 +
13 +/**
14 + * Manages EntryField repository operations.
15 + */
16 +class EntryFieldManager
17 +{
18 + private EntryFieldRepositoryInterface $entryFieldRepository;
19 + private EntryRepositoryInterface $entryRepository;
20 + private EntryFieldValueManager $valueManager;
21 +
22 + public function __construct(
23 + EntryFieldRepositoryInterface $entryFieldRepository,
24 + EntryRepositoryInterface $entryRepository,
25 + EntryFieldValueManager $valueManager
26 + ) {
27 + $this->entryFieldRepository = $entryFieldRepository;
28 + $this->entryRepository = $entryRepository;
29 + $this->valueManager = $valueManager;
30 + }
31 +
32 + /**
33 + * Fetch entries along with their associated fields.
34 + * Automatically formats field values for display.
35 + *
36 + * @param array<int, array<string, mixed>> $entries
37 + * @param bool $skipFormatting Whether to skip formatting and return raw values (used for result tables).
38 + * @return array<mixed>
39 + * @SuppressWarnings(PHPMD)
40 + */
41 + public function getEntryFields(array $entries, bool $skipFormatting = false): array
42 + {
43 + $entryFields = $this->entryRepository->getEntryFields($entries);
44 + return $this->valueManager->formatForFrontend($entryFields, $skipFormatting);
45 + }
46 +
47 + /**
48 + * Check if a value already exists in entry fields for a specific field.
49 + *
50 + * @param int $formId
51 + * @param int $fieldId
52 + * @param string $value
53 + * @return bool
54 + */
55 + public function checkDuplicateValue(
56 + int $formId,
57 + int $fieldId,
58 + string $value,
59 + ?int $excludeEntryId = null
60 + ): bool {
61 + return $this->entryFieldRepository->checkDuplicateValue(
62 + $formId,
63 + $fieldId,
64 + $value,
65 + $excludeEntryId
66 + );
67 + }
68 +
69 + /**
70 + * Add entry fields to the repository.
71 + *
72 + * Resolves all field values in PHP, then persists with a single multi-row INSERT.
73 + *
74 + * @param array<int, object> $formFields
75 + * @param int $entryId
76 + * @param array<mixed> $submissionData
77 + * @throws ValidationException
78 + */
79 + public function addEntryFields(array $formFields, int $entryId, array $submissionData): void
80 + {
81 + $parentChildrenMap = EntryHelper::buildParentChildrenMap($formFields);
82 + $parentSubfieldKeys = EntryHelper::buildParentSubfieldKeys(
83 + $parentChildrenMap,
84 + $submissionData,
85 + $formFields
86 + );
87 +
88 + /** @var list<array{entryField: EntryField, field: object}> $created */
89 + $created = [];
90 +
91 + foreach ($formFields as $field) {
92 + // Skip security/CAPTCHA fields - their tokens are only needed for verification, not storage
93 + $fieldType = $field->getType();
94 + if (FieldHelper::isSecurityField($fieldType)) {
95 + continue;
96 + }
97 +
98 + /** @var bool $shouldSkip */
99 + $shouldSkip = apply_filters('ivyforms/entry/field/should_skip', false, $field);
100 + if ($shouldSkip) {
101 + continue;
102 + }
103 +
104 + $value = $this->valueManager->resolveFieldValue(
105 + $field,
106 + $submissionData,
107 + $parentChildrenMap,
108 + $parentSubfieldKeys
109 + );
110 +
111 + $entryFieldData = [
112 + 'entryId' => $entryId,
113 + 'fieldId' => $field->getId(),
114 + 'fieldValue' => $value,
115 + ];
116 +
117 + /**
118 + * Filters the entry field data before creating the entry field object.
119 + * Allows modification of entry data before persistence.
120 + *
121 + * @since 0.1.0
122 + *
123 + * @param mixed[] $entryFieldData The entry field data array.
124 + * @param object $field The field object.
125 + * @param mixed[] $submissionData The submission data array.
126 + * @return mixed[] The modified entry field data array.
127 + */
128 + $entryFieldData = apply_filters(
129 + 'ivyforms/entry/field/before_create',
130 + $entryFieldData,
131 + $field,
132 + $submissionData
133 + );
134 +
135 + /**
136 + * Filters the entry field data for a specific field type before creating the entry field object.
137 + * Allows dynamic hook registration per field type
138 + *
139 + * @since 0.1.0
140 + *
141 + * @param mixed[] $entryFieldData The entry field data array.
142 + * @param object $field The field object.
143 + * @param mixed[] $submissionData The submission data array.
144 + * @return mixed[] The modified entry field data array.
145 + */
146 + $entryFieldData = apply_filters(
147 + "ivyforms/entry/field/before_create/{$field->getType()}",
148 + $entryFieldData,
149 + $field,
150 + $submissionData
151 + );
152 +
153 + $created[] = [
154 + 'entryField' => EntryFieldFactory::create($entryFieldData),
155 + 'field' => $field,
156 + ];
157 + }
158 +
159 + if ($created === []) {
160 + return;
161 + }
162 +
163 + $this->entryFieldRepository->batchInsert(
164 + array_column($created, 'entryField')
165 + );
166 +
167 + foreach ($created as $item) {
168 + $entryField = $item['entryField'];
169 + $field = $item['field'];
170 +
171 + /**
172 + * Action fired after an entry field has been saved to the database.
173 + * Allows post-processing or logging of entry field creation.
174 + *
175 + * @since 0.1.0
176 + *
177 + * @param object $entryField The created entry field object.
178 + * @param object $field The field object.
179 + * @param mixed[] $submissionData The submission data array.
180 + */
181 + do_action(
182 + 'ivyforms/entry/field/after_create',
183 + $entryField,
184 + $field,
185 + $submissionData
186 + );
187 +
188 + /**
189 + * Action fired after an entry field of a specific type has been saved to the database.
190 + * Allows dynamic hook registration per field type
191 + *
192 + * @since 0.1.0
193 + *
194 + * @param object $entryField The created entry field object.
195 + * @param object $field The field object.
196 + * @param mixed[] $submissionData The submission data array.
197 + */
198 + do_action(
199 + "ivyforms/entry/field/after_create/{$field->getType()}",
200 + $entryField,
201 + $field,
202 + $submissionData
203 + );
204 + }
205 + }
206 +}