PluginProbe
The Innovative Form Builder – IvyForms / 1.4
The Innovative Form Builder – IvyForms v1.4
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 / Form / FormRepository.php

FormRepository.php in The Innovative Form Builder – IvyForms 1.4, at backend/src/Repository/Form/FormRepository.php

416 lines 11.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\Form;
9
10 use IvyForms\Common\Exceptions\QueryExecutionException;
11 use IvyForms\Common\Helpers\FormPageHelper;
12 use IvyForms\Common\Helpers\FormPersistenceHelper;
13 use IvyForms\Entity\Form\Form;
14 use IvyForms\Factory\Form\FormFactory;
15 use IvyForms\Repository\AbstractRepository;
16 use IvyForms\Repository\VisibleFormIdsQueryFilter;
17 use IvyForms\Services\Translations\BackendStrings;
18
19 class FormRepository extends AbstractRepository implements FormRepositoryInterface
20 {
21 public const FACTORY = FormFactory::class;
22
23 // Column constants
24 public const COLUMN_STARRED = 'starred';
25
26 public const COLUMN_DATE_CREATED = 'dateCreated';
27
28
29 /**
30 * Add form to the database
31 *
32 * @param Form $entity
33 *
34 * @return int
35 *
36 * @throws QueryExecutionException
37 */
38 public function add($entity): int
39 {
40 $data = $entity->toArray();
41
42 if (!empty($data['fields']) && !empty($data['pages'])) {
43 $fieldsByPage = FormPageHelper::groupFieldsByPageId($data['fields']);
44 $data['pages'] = FormPageHelper::assignFieldsToPages($data['pages'], $fieldsByPage);
45 }
46
47 $result = $this->wpdb->insert(
48 $this->table,
49 FormPersistenceHelper::buildInsertRow($data),
50 ['%s', '%s', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s']
51 );
52
53 if ($result === false) {
54 throw new QueryExecutionException(
55 BackendStrings::getExceptionStrings()['unable_to_add_data'] . __CLASS__
56 );
57 }
58
59 return $this->wpdb->insert_id;
60 }
61
62 /**
63 * Update form in the database
64 *
65 * @param int $id
66 * @param Form $entity
67 *
68 * @return bool
69 *
70 * @throws QueryExecutionException
71 */
72 public function update(int $id, $entity): bool
73 {
74 $data = $entity->toArray();
75
76 if (!empty($data['fields']) && !empty($data['pages'])) {
77 $fieldsByPage = FormPageHelper::groupFieldsByPageId($data['fields']);
78 $data['pages'] = FormPageHelper::assignFieldsToPages($data['pages'], $fieldsByPage);
79 }
80
81 $result = $this->wpdb->update(
82 $this->table,
83 FormPersistenceHelper::buildUpdateRow($data),
84 ['id' => $id],
85 ['%s', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s'],
86 ['%d']
87 );
88
89 if ($result === false) {
90 throw new QueryExecutionException(BackendStrings::getAllFormsStrings()['unable_to_save_data'] . __CLASS__);
91 }
92
93 return $result;
94 }
95
96 /**
97 * Update the form starred value by ID.
98 *
99 * @param int $id
100 * @param string $value
101 *
102 * @return bool
103 * @throws QueryExecutionException
104 */
105 public function updateFormStarred(int $id, string $value): bool
106 {
107 // Update the starred column in the database
108 $result = $this->wpdb->update(
109 $this->table,
110 ['starred' => $value],
111 ['id' => $id],
112 ['%d'],
113 ['%d']
114 );
115
116 if ($result === false) {
117 throw new QueryExecutionException(BackendStrings::getAllFormsStrings()['unable_to_save_data'] . __CLASS__);
118 }
119
120 return $result;
121 }
122
123 /**
124 * Update the published status of a form by ID.
125 *
126 * @param int $formId
127 * @param string $value
128 *
129 * @return bool
130 * @throws QueryExecutionException
131 */
132 public function updateFormStatus(int $formId, string $value): bool
133 {
134 // Update the published column in the database
135 $result = $this->wpdb->update(
136 $this->table,
137 ['published' => $value],
138 ['id' => $formId],
139 ['%d'],
140 ['%d']
141 );
142
143 if ($result === false) {
144 throw new QueryExecutionException(BackendStrings::getAllFormsStrings()['unable_to_save_data'] . __CLASS__);
145 }
146
147 return $result;
148 }
149
150 /**
151 * Get the count of filters for the filter dropdown.
152 *
153 * @return array<string, int>
154 * @throws QueryExecutionException
155 */
156 public function getFilterCount(): array
157 {
158 $result = $this->wpdb->get_row(
159 $this->wpdb->prepare(
160 "SELECT
161 SUM(published = 1) as publishedTrueCount,
162 SUM(published = 0) as publishedFalseCount,
163 SUM(starred = 1) as starredTrueCount,
164 SUM(starred = 0) as starredFalseCount
165 FROM {$this->table}"
166 ),
167 ARRAY_A
168 );
169 if ($result === false) {
170 throw new QueryExecutionException(
171 BackendStrings::getExceptionStrings()['unable_search_entries'] . __CLASS__
172 );
173 }
174 // Convert all values to integers and provide defaults if query returns null
175 return array_map('intval', $result ?: [
176 'publishedTrueCount' => 0,
177 'publishedFalseCount' => 0,
178 'starredTrueCount' => 0,
179 'starredFalseCount' => 0,
180 ]);
181 }
182
183 /**
184 * Get the earliest form creation timestamp.
185 *
186 * @return string|null DATETIME as stored in the database
187 * @throws QueryExecutionException
188 */
189 public function getEarliestCreatedAt(): ?string
190 {
191 $column = self::COLUMN_DATE_CREATED;
192 $result = $this->wpdb->get_var(
193 "SELECT MIN(`{$column}`) FROM {$this->table} WHERE `{$column}` IS NOT NULL"
194 );
195
196 if ($result === false) {
197 throw new QueryExecutionException(
198 BackendStrings::getExceptionStrings()['unable_search_entries'] . __CLASS__
199 );
200 }
201
202 if ($result === null || $result === '') {
203 return null;
204 }
205
206 return (string) $result;
207 }
208
209 /**
210 * Check if a form exists by its ID.
211 *
212 * @param int $formId
213 *
214 * @return bool
215 * @throws QueryExecutionException
216 */
217 public function exists(int $formId): bool
218 {
219 $query = $this->wpdb->prepare(
220 "SELECT COUNT(*) FROM " . $this->table . " WHERE id = %d",
221 $formId
222 );
223 $count = $this->wpdb->get_var($query);
224 if ($count === false) {
225 throw new QueryExecutionException(
226 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
227 );
228 }
229 return (int)$count > 0;
230 }
231
232 /**
233 * @param list<int> $formIds
234 * @return list<int>
235 * @throws QueryExecutionException
236 */
237 public function filterExistingIds(array $formIds): array
238 {
239 $formIds = array_values(array_unique(array_filter(
240 array_map('intval', $formIds),
241 static function (int $id): bool {
242 return $id > 0;
243 }
244 )));
245
246 if ($formIds === []) {
247 return [];
248 }
249
250 $placeholders = implode(',', array_fill(0, count($formIds), '%d'));
251 $query = $this->wpdb->prepare(
252 "SELECT id FROM {$this->table} WHERE id IN ({$placeholders})",
253 ...$formIds
254 );
255 $rows = $this->wpdb->get_col($query);
256 if ($rows === null) {
257 throw new QueryExecutionException(
258 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
259 );
260 }
261
262 return array_map('intval', $rows);
263 }
264
265 /**
266 * @return list<int>
267 * @throws QueryExecutionException
268 */
269 public function getAllIds(): array
270 {
271 $rows = $this->wpdb->get_col("SELECT id FROM {$this->table} ORDER BY id ASC");
272 if ($rows === null) {
273 throw new QueryExecutionException(
274 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
275 );
276 }
277
278 return array_map('intval', $rows);
279 }
280
281 /**
282 * @return list<array{id:int, name:string}>
283 * @throws QueryExecutionException
284 */
285 public function getIdNamePairs(): array
286 {
287 $rows = $this->wpdb->get_results(
288 "SELECT id, name FROM {$this->table} ORDER BY name ASC",
289 ARRAY_A
290 );
291 if ($rows === null) {
292 throw new QueryExecutionException(
293 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
294 );
295 }
296
297 $pairs = [];
298 foreach ($rows as $row) {
299 if (!isset($row['id'], $row['name'])) {
300 continue;
301 }
302 $pairs[] = [
303 'id' => (int) $row['id'],
304 'name' => (string) $row['name'],
305 ];
306 }
307
308 return $pairs;
309 }
310
311 /**
312 * @param list<int> $formIds
313 * @return array<int, string>
314 * @throws QueryExecutionException
315 */
316 public function getNamesByIds(array $formIds): array
317 {
318 $formIds = array_values(array_unique(array_filter(
319 array_map('intval', $formIds),
320 static function (int $id): bool {
321 return $id > 0;
322 }
323 )));
324
325 if ($formIds === []) {
326 return [];
327 }
328
329 $placeholders = implode(',', array_fill(0, count($formIds), '%d'));
330 $query = $this->wpdb->prepare(
331 "SELECT id, name FROM {$this->table} WHERE id IN ({$placeholders})",
332 ...$formIds
333 );
334 $rows = $this->wpdb->get_results($query, ARRAY_A);
335 if ($rows === null) {
336 throw new QueryExecutionException(
337 BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__
338 );
339 }
340
341 $names = [];
342 foreach ($rows as $row) {
343 if (!isset($row['id'], $row['name'])) {
344 continue;
345 }
346 $names[(int) $row['id']] = (string) $row['name'];
347 }
348
349 return $names;
350 }
351
352 /**
353 * @param array<string, mixed>|null $params
354 * @param array<int, string> $whereClauses
355 * @param array<int|string, mixed> $queryParams
356 */
357 protected function addFilterClauses(?array $params, array &$whereClauses, array &$queryParams): void
358 {
359 parent::addFilterClauses($params, $whereClauses, $queryParams);
360
361 VisibleFormIdsQueryFilter::apply($params, $whereClauses, $queryParams, 'id');
362 }
363
364 /**
365 * Get searchable columns
366 *
367 * @return array<string>
368 */
369 protected function getSearchableColumns(): array
370 {
371 return ['name', 'author', 'description'];
372 }
373
374 /**
375 * Get filterable columns
376 *
377 * @return array<string>
378 */
379 protected function getFilterableColumns(): array
380 {
381 return ['starred', 'published'];
382 }
383
384 /**
385 * Get sortable columns
386 *
387 * @return array<string>
388 */
389 protected function getSortableColumns(): array
390 {
391 return ['id', 'name', 'author', 'dateCreated'];
392 }
393
394 /**
395 * Get the date column
396 *
397 * @return string
398 */
399 protected function getDateColumn(): string
400 {
401 return self::COLUMN_DATE_CREATED;
402 }
403
404 /**
405 * Get allowed columns for bulk update operations.
406 *
407 * @return string[]
408 */
409 protected function getAllowedBulkUpdateColumns(): array
410 {
411 return [
412 self::COLUMN_STARRED,
413 ];
414 }
415 }
416