PluginProbe
The Innovative Form Builder – IvyForms / 0.8
The Innovative Form Builder – IvyForms v0.8
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 1.2 1.3
ivyforms / backend / src / Repository / Field / FieldRepository.php

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

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