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

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