PluginProbe
The Innovative Form Builder – IvyForms / 1.1.1
The Innovative Form Builder – IvyForms v1.1.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 / Repository / Field / FieldRepository.php

FieldRepository.php in The Innovative Form Builder – IvyForms 1.1.1, at backend/src/Repository/Field/FieldRepository.php

383 lines 17.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 LICENCE.md for license details.
6 */
7
8 namespace IvyForms\Repository\Field;
9
10 use IvyForms\Common\Exceptions\InvalidArgumentException;
11 use IvyForms\Common\Exceptions\QueryExecutionException;
12 use IvyForms\Entity\Field\Field;
13 use IvyForms\Factory\Field\FieldFactory;
14 use IvyForms\Repository\AbstractRepository;
15 use IvyForms\Services\Translations\BackendStrings;
16
17 /**
18 * Class FieldRepository
19 *
20 * @package IvyForms\Repository\Field
21 */
22 class FieldRepository extends AbstractRepository implements FieldRepositoryInterface
23 {
24 public const FACTORY = FieldFactory::class;
25
26 /**
27 * Add field to the database
28 *
29 * @param Field $entity
30 *
31 * @return int
32 *
33 * @throws QueryExecutionException
34 */
35 public function add($entity): int
36 {
37
38 $data = $entity->toArray();
39
40 $result = $this->wpdb->insert(
41 $this->table,
42 [
43 'fieldIndex' => $data['fieldIndex'],
44 'formId' => $data['formId'],
45 'type' => $data['type'],
46 'label' => $data['label'],
47 'required' => (int)$data['required'],
48 'defaultValue' => $data['defaultValue'],
49 'placeholder' => $data['placeholder'],
50 'position' => $data['position'],
51 'rowIndex' => $data['rowIndex'] ?? 0,
52 'columnIndex' => $data['columnIndex'] ?? 0,
53 'width' => $data['width'] ?? 100,
54 'parentId' => $data['parentId'] ?? null,
55 'pageId' => $data['pageId'] ?? null,
56 'settings' => json_encode(
57 /**
58 * Allows modification of the settings data before saving to database.
59 * @since 0.1.0
60 *
61 * @param mixed[] $settings The current settings array.
62 * @param mixed[] $data The full field data array.
63 * @param Field $entity The Field entity instance.
64 * @return mixed[] The modified settings array.
65 */
66 apply_filters(
67 'ivyforms/repository/field/settings',
68 [
69 'hideLabel' => (int)$data['hideLabel'],
70 'readOnly' => (int)$data['readOnly'],
71 'description' => $data['description'],
72 'requiredMessage' => $data['requiredMessage'],
73 'cssClasses' => $data['cssClasses'],
74 'limitMaxLength' => (int)$data['limitMaxLength'],
75 'limitRange' => (int)$data['limitRange'],
76 'maxLength' => $data['maxLength'],
77 'labelPosition' => $data['labelPosition'],
78 'noDuplicates' => (int)$data['noDuplicates'],
79 'shuffleOptions' => (int)$data['shuffleOptions'],
80 'showValues' => (int)$data['showValues'],
81 'enableSearch' => (int)$data['enableSearch'],
82 'rows' => (int)$data['rows'],
83 'confirmFieldEnabled' => (int)($data['confirmFieldEnabled'] ?? 0),
84 'confirmFieldLabel' => $data['confirmFieldLabel'] ?? '',
85 'confirmFieldPlaceholder' => $data['confirmFieldPlaceholder'] ?? '',
86 'confirmFieldHideLabel' => (int)($data['confirmFieldHideLabel'] ?? 0),
87 'phoneFormat' => $data['phoneFormat'],
88 'phoneAutoDetect' => $data['phoneAutoDetect'],
89 'minValue' => isset($data['minValue']) ? (float)$data['minValue'] : null,
90 'maxValue' => isset($data['maxValue']) ? (float)$data['maxValue'] : null,
91 'step' => (float)$data['step'],
92 'showGrid' => (int)($data['showGrid'] ?? 0),
93 'numberFormat' => $data['numberFormat'] ?? '',
94 'visible' => (int)$data['visible'],
95 'inputPrefix' => $data['inputPrefix'] ?? '',
96 'inputSuffix' => $data['inputSuffix'] ?? '',
97 'timeFieldType' => $data['timeFieldType'] ?? '',
98 'timeFormat' => $data['timeFormat'] ?? '',
99 'dateFieldType' => $data['dateFieldType'] ?? '',
100 'dateFormat' => $data['dateFormat'] ?? '',
101 'minDateValue' => $data['minDateValue'] ?? '',
102 'maxDateValue' => $data['maxDateValue'] ?? '',
103 'showRatingText' => (int)($data['showRatingText'] ?? 0),
104 'ratingIcon' => $data['ratingIcon'] ?? 'star',
105 'htmlContent' => $data['htmlContent'] ?? '',
106 'agreementText' => $data['agreementText'] ?? '',
107 'limitDateRange' => (int)$data['limitDateRange'],
108 'minTimeValue' => $data['minTimeValue'] ?? '',
109 'maxTimeValue' => $data['maxTimeValue'] ?? '',
110 'limitTimeRange' => (int)$data['limitTimeRange'],
111 'nameFieldType' => $data['nameFieldType'] ?? '',
112 'subFieldIndex' => isset($data['subFieldIndex']) ? (int)$data['subFieldIndex'] : null,
113 ],
114 $data,
115 $entity
116 )
117 ),
118 'dateCreated' => current_time('mysql')
119 ],
120 ['%d', '%d', '%s', '%s', '%d', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%s', '%s', '%s']
121 );
122
123 if ($result === false) {
124 throw new QueryExecutionException(
125 BackendStrings::getExceptionStrings()['unable_to_add_data'] . __CLASS__
126 );
127 }
128
129 return $this->wpdb->insert_id;
130 }
131
132 /**
133 * Update field in the database
134 *
135 * @param int $id
136 * @param Field $entity
137 *
138 * @return bool
139 *
140 * @throws QueryExecutionException
141 */
142 public function update(int $id, $entity): bool
143 {
144
145 $data = $entity->toArray();
146
147 $result = $this->wpdb->update(
148 $this->table,
149 [
150 'fieldIndex' => $data['fieldIndex'],
151 'formId' => $data['formId'],
152 'type' => $data['type'],
153 'label' => $data['label'],
154 'required' => (int)$data['required'],
155 'defaultValue' => $data['defaultValue'],
156 'placeholder' => $data['placeholder'],
157 'position' => $data['position'],
158 'rowIndex' => $data['rowIndex'] ?? 0,
159 'columnIndex' => $data['columnIndex'] ?? 0,
160 'width' => $data['width'] ?? 100,
161 'parentId' => $data['parentId'] ?? null,
162 'pageId' => $data['pageId'] ?? null,
163 'settings' => json_encode(
164 /**
165 * Allows modification of the settings data before updating database.
166 * @since 0.1.0
167 *
168 * @param mixed[] $settings The current settings array.
169 * @param mixed[] $data The full field data array.
170 * @param Field $entity The Field entity instance.
171 * @return mixed[] The modified settings array.
172 */
173 apply_filters(
174 'ivyforms/repository/field/settings',
175 [
176 'hideLabel' => (int)$data['hideLabel'],
177 'readOnly' => (int)$data['readOnly'],
178 'description' => $data['description'],
179 'requiredMessage' => $data['requiredMessage'],
180 'cssClasses' => $data['cssClasses'],
181 'limitMaxLength' => (int)$data['limitMaxLength'],
182 'limitRange' => filter_var($data['limitRange'], FILTER_VALIDATE_BOOLEAN) ? 1 : 0,
183 'maxLength' => $data['maxLength'],
184 'labelPosition' => $data['labelPosition'],
185 'noDuplicates' => (int)$data['noDuplicates'],
186 'shuffleOptions' => (int)$data['shuffleOptions'],
187 'showValues' => (int)$data['showValues'],
188 'enableSearch' => (int)$data['enableSearch'],
189 'rows' => (int)$data['rows'],
190 'confirmFieldEnabled' => (int)($data['confirmFieldEnabled'] ?? 0),
191 'confirmFieldLabel' => $data['confirmFieldLabel'] ?? '',
192 'confirmFieldPlaceholder' => $data['confirmFieldPlaceholder'] ?? '',
193 'confirmFieldHideLabel' => (int)($data['confirmFieldHideLabel'] ?? 0),
194 'phoneFormat' => $data['phoneFormat'],
195 'phoneAutoDetect' => $data['phoneAutoDetect'],
196 'minValue' => isset($data['minValue']) ? (float)$data['minValue'] : null,
197 'maxValue' => isset($data['maxValue']) ? (float)$data['maxValue'] : null,
198 'step' => (float)$data['step'],
199 'showGrid' => (int)($data['showGrid'] ?? 0),
200 'numberFormat' => $data['numberFormat'] ?? '',
201 'visible' => array_key_exists('visible', $data) ? (int)$data['visible'] : 1,
202 'inputPrefix' => $data['inputPrefix'] ?? '',
203 'inputSuffix' => $data['inputSuffix'] ?? '',
204 'timeFieldType' => $data['timeFieldType'] ?? '',
205 'timeFormat' => $data['timeFormat'] ?? '',
206 'dateFieldType' => $data['dateFieldType'] ?? '',
207 'dateFormat' => $data['dateFormat'] ?? '',
208 'minDateValue' => $data['minDateValue'] ?? '',
209 'maxDateValue' => $data['maxDateValue'] ?? '',
210 'showRatingText' => (int)($data['showRatingText'] ?? 0),
211 'ratingIcon' => $data['ratingIcon'] ?? 'star',
212 'htmlContent' => $data['htmlContent'] ?? '',
213 'agreementText' => $data['agreementText'] ?? '',
214 'limitDateRange' => (int)$data['limitDateRange'],
215 'minTimeValue' => $data['minTimeValue'] ?? '',
216 'maxTimeValue' => $data['maxTimeValue'] ?? '',
217 'limitTimeRange' => (int)$data['limitTimeRange'],
218 'nameFieldType' => $data['nameFieldType'] ?? '',
219 'subFieldIndex' => isset($data['subFieldIndex']) ? (int)$data['subFieldIndex'] : null,
220 ],
221 $data,
222 $entity
223 )
224 ),
225 ],
226 ['id' => $data['id']],
227 ['%d', '%d', '%s', '%s', '%d', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%s', '%s'],
228 ['%d']
229 );
230
231 if ($result === false) {
232 throw new QueryExecutionException(BackendStrings::getAllFormsStrings()['unable_to_save_data'] . __CLASS__);
233 }
234
235 return $result;
236 }
237
238 /**
239 * Get fields by form ID
240 *
241 * @param int $id
242 *
243 * @return mixed[]
244 * @throws QueryExecutionException
245 */
246 public function getFieldsById(int $id): array
247 {
248 $rows = $this->wpdb->get_results(
249 $this->wpdb->prepare(
250 $this->selectQuery() . " WHERE $this->table.formId = %d ORDER BY $this->table.position ASC",
251 $id
252 ),
253 ARRAY_A
254 );
255 if ($rows === false) {
256 throw new QueryExecutionException(
257 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
258 );
259 }
260 $result = [];
261 foreach ($rows as $row) {
262 if (array_key_exists('parentId', $row)) {
263 $row['parentId'] = $row['parentId'] !== null ? (int)$row['parentId'] : null;
264 }
265 $result[] = call_user_func([static::FACTORY, 'create'], $row);
266 }
267 return $result;
268 }
269
270 /**
271 * Get multiple fields by their IDs in a single query.
272 *
273 * @param int[] $fieldIds
274 * @return array<int, object> Indexed by field ID
275 * @throws QueryExecutionException
276 */
277 public function getFieldsByIds(array $fieldIds): array
278 {
279 if (empty($fieldIds)) {
280 return [];
281 }
282
283 $fieldIds = array_map('intval', $fieldIds);
284 $placeholders = implode(',', array_fill(0, count($fieldIds), '%d'));
285 $rows = $this->wpdb->get_results(
286 $this->wpdb->prepare(
287 $this->selectQuery() . " WHERE $this->table.id IN ($placeholders) ORDER BY $this->table.position ASC",
288 ...$fieldIds
289 ),
290 ARRAY_A
291 );
292
293 if ($rows === false) {
294 throw new QueryExecutionException(
295 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
296 );
297 }
298
299 $result = [];
300 foreach ($rows as $row) {
301 if (array_key_exists('parentId', $row)) {
302 $row['parentId'] = $row['parentId'] !== null ? (int)$row['parentId'] : null;
303 }
304 $field = call_user_func([static::FACTORY, 'create'], $row);
305 $result[$field->getId()] = $field;
306 }
307
308 return $result;
309 }
310
311 /**
312 * Delete multiple fields by their IDs in bulk, and their field options.
313 *
314 * @param array<int> $ids
315 * @return int Number of deleted fields
316 * @throws QueryExecutionException
317 */
318 public function deleteMany(array $ids): int
319 {
320 if (empty($ids)) {
321 return 0;
322 }
323 $placeholders = implode(',', array_fill(0, count($ids), '%d'));
324 $deleteFieldsQuery = "DELETE FROM {$this->table} WHERE id IN ($placeholders)";
325 $result = $this->wpdb->query($this->wpdb->prepare($deleteFieldsQuery, ...$ids));
326 if ($result === false) {
327 throw new QueryExecutionException(
328 sprintf(
329 BackendStrings::getExceptionStrings()['failed_delete_by_ids'],
330 implode(', ', $ids),
331 $this->table
332 )
333 );
334 }
335 return $result;
336 }
337
338 /**
339 * Delete multiple fields by foreign key values (formId), and their field options.
340 *
341 * @param array<int> $formIds
342 * @param string $foreignColumn
343 * @return int Number of deleted fields
344 * @throws QueryExecutionException
345 */
346 public function deleteManyByForeignKeyValues(array $formIds, string $foreignColumn = 'formId'): int
347 {
348 if (empty($formIds)) {
349 return 0;
350 }
351 $formIds = array_map('intval', $formIds);
352 $placeholders = implode(',', array_fill(0, count($formIds), '%d'));
353 $deleteFieldsQuery = "DELETE FROM {$this->table} WHERE {$foreignColumn} IN ($placeholders)";
354 $result = $this->wpdb->query($this->wpdb->prepare($deleteFieldsQuery, ...$formIds));
355 if ($result === false) {
356 throw new QueryExecutionException(
357 BackendStrings::getExceptionStrings()['failed_delete_by_foreign_keys']
358 );
359 }
360 return $result;
361 }
362
363 /**
364 * Delete fields by a single foreign key value (formId), and their field options.
365 *
366 * @param int $formId
367 * @param string $foreignColumn
368 * @return int Number of deleted fields
369 * @throws QueryExecutionException
370 */
371 public function deleteOneByForeignKeyValue(int $formId, string $foreignColumn = 'formId'): int
372 {
373 $deleteFieldsQuery = "DELETE FROM {$this->table} WHERE {$foreignColumn} = %d";
374 $result = $this->wpdb->query($this->wpdb->prepare($deleteFieldsQuery, $formId));
375 if ($result === false) {
376 throw new QueryExecutionException(
377 BackendStrings::getExceptionStrings()['failed_delete_by_foreign_key']
378 );
379 }
380 return $result;
381 }
382 }
383