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

379 lines 16.7 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 ],
112 $data,
113 $entity
114 )
115 ),
116 'dateCreated' => current_time('mysql')
117 ],
118 ['%d', '%d', '%s', '%s', '%d', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%s', '%s', '%s']
119 );
120
121 if ($result === false) {
122 throw new QueryExecutionException(
123 BackendStrings::getExceptionStrings()['unable_to_add_data'] . __CLASS__
124 );
125 }
126
127 return $this->wpdb->insert_id;
128 }
129
130 /**
131 * Update field in the database
132 *
133 * @param int $id
134 * @param Field $entity
135 *
136 * @return bool
137 *
138 * @throws QueryExecutionException
139 */
140 public function update(int $id, $entity): bool
141 {
142
143 $data = $entity->toArray();
144
145 $result = $this->wpdb->update(
146 $this->table,
147 [
148 'fieldIndex' => $data['fieldIndex'],
149 'formId' => $data['formId'],
150 'type' => $data['type'],
151 'label' => $data['label'],
152 'required' => (int)$data['required'],
153 'defaultValue' => $data['defaultValue'],
154 'placeholder' => $data['placeholder'],
155 'position' => $data['position'],
156 'rowIndex' => $data['rowIndex'] ?? 0,
157 'columnIndex' => $data['columnIndex'] ?? 0,
158 'width' => $data['width'] ?? 100,
159 'parentId' => $data['parentId'] ?? null,
160 'pageId' => $data['pageId'] ?? null,
161 'settings' => json_encode(
162 /**
163 * Allows modification of the settings data before updating database.
164 * @since 0.1.0
165 *
166 * @param mixed[] $settings The current settings array.
167 * @param mixed[] $data The full field data array.
168 * @param Field $entity The Field entity instance.
169 * @return mixed[] The modified settings array.
170 */
171 apply_filters(
172 'ivyforms/repository/field/settings',
173 [
174 'hideLabel' => (int)$data['hideLabel'],
175 'readOnly' => (int)$data['readOnly'],
176 'description' => $data['description'],
177 'requiredMessage' => $data['requiredMessage'],
178 'cssClasses' => $data['cssClasses'],
179 'limitMaxLength' => (int)$data['limitMaxLength'],
180 'limitRange' => filter_var($data['limitRange'], FILTER_VALIDATE_BOOLEAN) ? 1 : 0,
181 'maxLength' => $data['maxLength'],
182 'labelPosition' => $data['labelPosition'],
183 'noDuplicates' => (int)$data['noDuplicates'],
184 'shuffleOptions' => (int)$data['shuffleOptions'],
185 'showValues' => (int)$data['showValues'],
186 'enableSearch' => (int)$data['enableSearch'],
187 'rows' => (int)$data['rows'],
188 'confirmFieldEnabled' => (int)($data['confirmFieldEnabled'] ?? 0),
189 'confirmFieldLabel' => $data['confirmFieldLabel'] ?? '',
190 'confirmFieldPlaceholder' => $data['confirmFieldPlaceholder'] ?? '',
191 'confirmFieldHideLabel' => (int)($data['confirmFieldHideLabel'] ?? 0),
192 'phoneFormat' => $data['phoneFormat'],
193 'phoneAutoDetect' => $data['phoneAutoDetect'],
194 'minValue' => isset($data['minValue']) ? (float)$data['minValue'] : null,
195 'maxValue' => isset($data['maxValue']) ? (float)$data['maxValue'] : null,
196 'step' => (float)$data['step'],
197 'showGrid' => (int)($data['showGrid'] ?? 0),
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 'agreementText' => $data['agreementText'] ?? '',
212 'limitDateRange' => (int)$data['limitDateRange'],
213 'minTimeValue' => $data['minTimeValue'] ?? '',
214 'maxTimeValue' => $data['maxTimeValue'] ?? '',
215 'limitTimeRange' => (int)$data['limitTimeRange'],
216 ],
217 $data,
218 $entity
219 )
220 ),
221 ],
222 ['id' => $data['id']],
223 ['%d', '%d', '%s', '%s', '%d', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%s', '%s'],
224 ['%d']
225 );
226
227 if ($result === false) {
228 throw new QueryExecutionException(BackendStrings::getAllFormsStrings()['unable_to_save_data'] . __CLASS__);
229 }
230
231 return $result;
232 }
233
234 /**
235 * Get fields by form ID
236 *
237 * @param int $id
238 *
239 * @return mixed[]
240 * @throws QueryExecutionException
241 */
242 public function getFieldsById(int $id): array
243 {
244 $rows = $this->wpdb->get_results(
245 $this->wpdb->prepare(
246 $this->selectQuery() . " WHERE $this->table.formId = %d ORDER BY $this->table.position ASC",
247 $id
248 ),
249 ARRAY_A
250 );
251 if ($rows === false) {
252 throw new QueryExecutionException(
253 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
254 );
255 }
256 $result = [];
257 foreach ($rows as $row) {
258 if (array_key_exists('parentId', $row)) {
259 $row['parentId'] = $row['parentId'] !== null ? (int)$row['parentId'] : null;
260 }
261 $result[] = call_user_func([static::FACTORY, 'create'], $row);
262 }
263 return $result;
264 }
265
266 /**
267 * Get multiple fields by their IDs in a single query.
268 *
269 * @param int[] $fieldIds
270 * @return array<int, object> Indexed by field ID
271 * @throws QueryExecutionException
272 */
273 public function getFieldsByIds(array $fieldIds): array
274 {
275 if (empty($fieldIds)) {
276 return [];
277 }
278
279 $fieldIds = array_map('intval', $fieldIds);
280 $placeholders = implode(',', array_fill(0, count($fieldIds), '%d'));
281 $rows = $this->wpdb->get_results(
282 $this->wpdb->prepare(
283 $this->selectQuery() . " WHERE $this->table.id IN ($placeholders) ORDER BY $this->table.position ASC",
284 ...$fieldIds
285 ),
286 ARRAY_A
287 );
288
289 if ($rows === false) {
290 throw new QueryExecutionException(
291 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
292 );
293 }
294
295 $result = [];
296 foreach ($rows as $row) {
297 if (array_key_exists('parentId', $row)) {
298 $row['parentId'] = $row['parentId'] !== null ? (int)$row['parentId'] : null;
299 }
300 $field = call_user_func([static::FACTORY, 'create'], $row);
301 $result[$field->getId()] = $field;
302 }
303
304 return $result;
305 }
306
307 /**
308 * Delete multiple fields by their IDs in bulk, and their field options.
309 *
310 * @param array<int> $ids
311 * @return int Number of deleted fields
312 * @throws QueryExecutionException
313 */
314 public function deleteMany(array $ids): int
315 {
316 if (empty($ids)) {
317 return 0;
318 }
319 $placeholders = implode(',', array_fill(0, count($ids), '%d'));
320 $deleteFieldsQuery = "DELETE FROM {$this->table} WHERE id IN ($placeholders)";
321 $result = $this->wpdb->query($this->wpdb->prepare($deleteFieldsQuery, ...$ids));
322 if ($result === false) {
323 throw new QueryExecutionException(
324 sprintf(
325 BackendStrings::getExceptionStrings()['failed_delete_by_ids'],
326 implode(', ', $ids),
327 $this->table
328 )
329 );
330 }
331 return $result;
332 }
333
334 /**
335 * Delete multiple fields by foreign key values (formId), and their field options.
336 *
337 * @param array<int> $formIds
338 * @param string $foreignColumn
339 * @return int Number of deleted fields
340 * @throws QueryExecutionException
341 */
342 public function deleteManyByForeignKeyValues(array $formIds, string $foreignColumn = 'formId'): int
343 {
344 if (empty($formIds)) {
345 return 0;
346 }
347 $formIds = array_map('intval', $formIds);
348 $placeholders = implode(',', array_fill(0, count($formIds), '%d'));
349 $deleteFieldsQuery = "DELETE FROM {$this->table} WHERE {$foreignColumn} IN ($placeholders)";
350 $result = $this->wpdb->query($this->wpdb->prepare($deleteFieldsQuery, ...$formIds));
351 if ($result === false) {
352 throw new QueryExecutionException(
353 BackendStrings::getExceptionStrings()['failed_delete_by_foreign_keys']
354 );
355 }
356 return $result;
357 }
358
359 /**
360 * Delete fields by a single foreign key value (formId), and their field options.
361 *
362 * @param int $formId
363 * @param string $foreignColumn
364 * @return int Number of deleted fields
365 * @throws QueryExecutionException
366 */
367 public function deleteOneByForeignKeyValue(int $formId, string $foreignColumn = 'formId'): int
368 {
369 $deleteFieldsQuery = "DELETE FROM {$this->table} WHERE {$foreignColumn} = %d";
370 $result = $this->wpdb->query($this->wpdb->prepare($deleteFieldsQuery, $formId));
371 if ($result === false) {
372 throw new QueryExecutionException(
373 BackendStrings::getExceptionStrings()['failed_delete_by_foreign_key']
374 );
375 }
376 return $result;
377 }
378 }
379