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

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