PluginProbe
The Innovative Form Builder – IvyForms / 0.9
The Innovative Form Builder – IvyForms v0.9
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 0.9, at backend/src/Repository/Field/FieldRepository.php

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