| @@ -1,23 +1,21 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | /** |
| 4 | - * @copyright © TMS-Plugins. All rights reserved. | |
| 4 | + * @copyright © Melograno Venture Studio. All rights reserved. | |
| 5 | 5 | * @licence See LICENCE.md for license details. |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace IvyForms\Repository\Entry; |
| 9 | 9 | |
| 10 | -// phpcs:disable PSR1.Files.SideEffects | |
| 11 | -if (!defined('ABSPATH')) { | |
| 12 | - exit; // Exit if accessed directly | |
| 13 | -} | |
| 14 | - | |
| 15 | 10 | use IvyForms\Common\Exceptions\InvalidArgumentException; |
| 16 | 11 | use IvyForms\Common\Exceptions\QueryExecutionException; |
| 12 | +use IvyForms\Common\Helpers\EntryBatchUpdater; | |
| 13 | +use IvyForms\Common\Helpers\EntryQueryHelper; | |
| 17 | 14 | use IvyForms\Entity\Entry\Entry; |
| 18 | 15 | use IvyForms\Factory\Entry\EntryFactory; |
| 19 | 16 | use IvyForms\Repository\AbstractRepository; |
| 17 | +use IvyForms\Repository\VisibleFormIdsQueryFilter; | |
| 20 | 18 | use IvyForms\Services\InstallActions\DB\Entry\EntriesTable; |
| 21 | 19 | use IvyForms\Services\InstallActions\DB\EntryField\EntryFieldsTable as EntryFieldsTable; |
| 22 | 20 | use IvyForms\Services\InstallActions\DB\Form\FormsTable; |
| 23 | 21 | use IvyForms\Services\Translations\BackendStrings; |
| @@ -25,8 +23,12 @@ | ||
| 25 | 23 | class EntryRepository extends AbstractRepository implements EntryRepositoryInterface |
| 26 | 24 | { |
| 27 | 25 | public const FACTORY = EntryFactory::class; |
| 28 | 26 | |
| 27 | + // Column constants | |
| 28 | + public const COLUMN_STATUS = 'status'; | |
| 29 | + public const COLUMN_STARRED = 'starred'; | |
| 30 | + | |
| 29 | 31 | /** |
| 30 | 32 | * Add entry to the database |
| 31 | 33 | * |
| 32 | 34 | * @param Entry $entity |
| @@ -36,17 +38,20 @@ | ||
| 36 | 38 | * @throws QueryExecutionException |
| 37 | 39 | */ |
| 38 | 40 | public function add($entity): int |
| 39 | 41 | { |
| 40 | - $data = $entity->getData(); | |
| 42 | + $data = $entity->toArray(true); | |
| 41 | 43 | |
| 44 | + $dateCreated = !empty($data['dateCreated']) ? (string)$data['dateCreated'] : current_time('mysql'); | |
| 45 | + $dateEdited = !empty($data['dateEdited']) ? (string)$data['dateEdited'] : $dateCreated; | |
| 46 | + | |
| 42 | 47 | $result = $this->wpdb->insert( |
| 43 | 48 | $this->table, |
| 44 | 49 | [ |
| 45 | 50 | 'formId' => $data['formId'], |
| 46 | 51 | 'userId' => $data['userId'], |
| 47 | - 'dateCreated' => current_time('mysql'), | |
| 48 | - 'dateEdited' => current_time('mysql'), | |
| 52 | + 'dateCreated' => $dateCreated, | |
| 53 | + 'dateEdited' => $dateEdited, | |
| 49 | 54 | 'status' => $data['status'], |
| 50 | 55 | 'ipAddress' => $data['ipAddress'], |
| 51 | 56 | 'userAgent' => $data['userAgent'], |
| 52 | 57 | 'sourceURL' => $data['sourceURL'], |
| @@ -166,33 +171,39 @@ | ||
| 166 | 171 | $whereClauses = $this->buildWhereClauses($params, $queryParams); |
| 167 | 172 | |
| 168 | 173 | // Always join entry fields and forms for search/filter/sort |
| 169 | 174 | $entriesTable = EntriesTable::getTableName(); |
| 170 | - $entryFieldsTable = EntryFieldsTable::getTableName(); | |
| 175 | + $join = EntryQueryHelper::getEntryJoinClause(); | |
| 171 | 176 | $formsTable = FormsTable::getTableName(); |
| 172 | - $join = " LEFT JOIN {$entryFieldsTable} eft ON e.id = eft.entryId "; | |
| 173 | - $join .= " LEFT JOIN {$formsTable} f ON e.formId = f.id "; | |
| 174 | 177 | |
| 175 | 178 | // Sorting |
| 176 | 179 | $sortableColumns = $this->getSortableColumns(); |
| 177 | 180 | $sortBy = $params['orderBy'] ?? 'id'; |
| 178 | 181 | $order = strtolower($params['order'] ?? 'asc') === 'asc' ? 'ASC' : 'DESC'; |
| 179 | - if (!in_array($sortBy, $sortableColumns, true)) { | |
| 180 | - $sortBy = 'id'; | |
| 182 | + // Map 'formName' to 'f.name' for sorting | |
| 183 | + $sortColumn = 'e.id'; | |
| 184 | + if ($sortBy === 'formName') { | |
| 185 | + $sortColumn = 'f.name'; | |
| 186 | + } elseif (in_array($sortBy, $sortableColumns, true)) { | |
| 187 | + $sortColumn = 'e.' . $sortBy; | |
| 181 | 188 | } |
| 182 | 189 | |
| 183 | 190 | // Pagination |
| 184 | 191 | $page = max(($params['page'] ?? 1), 1); |
| 185 | - $perPage = max(($params['perPage'] ?? 10), 1); | |
| 186 | - $offset = ($page - 1) * $perPage; | |
| 187 | - $queryParams[] = $perPage; | |
| 188 | - $queryParams[] = $offset; | |
| 189 | - | |
| 190 | - // Main query | |
| 191 | - $sql = "SELECT DISTINCT e.* FROM {$entriesTable} e $join | |
| 192 | - WHERE {$whereClauses} | |
| 193 | - ORDER BY e.{$sortBy} {$order} LIMIT %d OFFSET %d"; | |
| 194 | - $results = $this->wpdb->get_results($this->wpdb->prepare($sql, $queryParams), ARRAY_A); | |
| 192 | + $perPage = $params['perPage'] ?? 10; | |
| 193 | + $queryBuild = EntryQueryHelper::buildEntrySelectQuery( | |
| 194 | + $entriesTable, | |
| 195 | + $join, | |
| 196 | + $whereClauses, | |
| 197 | + $sortColumn, | |
| 198 | + $order, | |
| 199 | + $queryParams, | |
| 200 | + $perPage, | |
| 201 | + $page | |
| 202 | + ); | |
| 203 | + $sql = $queryBuild['sql']; | |
| 204 | + $mainParams = $queryBuild['params']; | |
| 205 | + $results = $this->wpdb->get_results($this->wpdb->prepare($sql, $mainParams), ARRAY_A); | |
| 195 | 206 | if ($results === false) { |
| 196 | 207 | throw new QueryExecutionException( |
| 197 | 208 | BackendStrings::getExceptionStrings()['unable_search_entries'] . __CLASS__ |
| 198 | 209 | ); |
| @@ -198,14 +209,29 @@ | ||
| 198 | 209 | ); |
| 199 | 210 | } |
| 200 | 211 | |
| 201 | 212 | // Total count for pagination meta (exclude LIMIT/OFFSET) |
| 202 | - $countParams = $queryParams; | |
| 203 | - array_pop($countParams); // offset | |
| 204 | - array_pop($countParams); // perPage | |
| 205 | 213 | $countSql = "SELECT COUNT(DISTINCT e.id) FROM {$entriesTable} e $join WHERE {$whereClauses}"; |
| 206 | - $total = (int)$this->wpdb->get_var($this->wpdb->prepare($countSql, $countParams)); | |
| 214 | + $total = (int)$this->wpdb->get_var($this->wpdb->prepare($countSql, $queryParams)); | |
| 207 | 215 | |
| 216 | + // Fetch form names for all unique formIds in the results | |
| 217 | + $formIdToName = []; | |
| 218 | + $formNamesQuery = EntryQueryHelper::getFormNamesByIdsQuery($results, $formsTable); | |
| 219 | + if (!empty($formNamesQuery['sql'])) { | |
| 220 | + $formRows = $this->wpdb->get_results( | |
| 221 | + $this->wpdb->prepare($formNamesQuery['sql'], $formNamesQuery['params']), | |
| 222 | + ARRAY_A | |
| 223 | + ); | |
| 224 | + if ($formRows === null) { | |
| 225 | + throw new QueryExecutionException( | |
| 226 | + BackendStrings::getExceptionStrings()['unable_get_form_names'] . __CLASS__ | |
| 227 | + ); | |
| 228 | + } | |
| 229 | + foreach ($formRows as $row) { | |
| 230 | + $formIdToName[$row['id']] = $row['name']; | |
| 231 | + } | |
| 232 | + } | |
| 233 | + | |
| 208 | 234 | return [ |
| 209 | 235 | 'data' => $results, |
| 210 | 236 | 'meta' => [ |
| 211 | 237 | 'page' => $page, |
| @@ -211,68 +237,39 @@ | ||
| 211 | 237 | 'page' => $page, |
| 212 | 238 | 'perPage' => $perPage, |
| 213 | 239 | 'total' => $total, |
| 214 | 240 | ], |
| 241 | + 'formIdToName' => $formIdToName, | |
| 215 | 242 | ]; |
| 216 | 243 | } |
| 217 | 244 | |
| 218 | 245 | /** |
| 219 | - * Override addSearchClauses to support searching fieldValue and form name. | |
| 220 | - * Extracted search conditions to a helper for complexity reduction. | |
| 221 | - * | |
| 222 | - * @param array<string, mixed>|null $params | |
| 223 | - * @param array<string> $whereClauses | |
| 224 | - * @param array<int|string, mixed> $queryParams | |
| 225 | - * | |
| 226 | - * @return void | |
| 246 | + * Override addSearchClauses to use EntryQueryHelper for search WHERE clause construction. | |
| 227 | 247 | */ |
| 228 | 248 | protected function addSearchClauses(?array $params, array &$whereClauses, array &$queryParams): void |
| 229 | 249 | { |
| 230 | - if (!empty($params['search'])) { | |
| 231 | - $searchEscaped = '%' . $this->wpdb->esc_like($params['search']) . '%'; | |
| 232 | - $searchConditions = $this->getEntrySearchConditions($params); | |
| 233 | - $whereClauses[] = '(' . implode(' OR ', $searchConditions) . ')'; | |
| 234 | - // Add the same number of params as conditions, no unused variable | |
| 235 | - $queryParams = array_merge($queryParams, array_fill(0, count($searchConditions), $searchEscaped)); | |
| 250 | + $searchResult = EntryQueryHelper::buildSearchWhereClause($params); | |
| 251 | + if ($searchResult['where']) { | |
| 252 | + $whereClauses[] = $searchResult['where']; | |
| 253 | + $queryParams = array_merge($queryParams, $searchResult['params']); | |
| 236 | 254 | } |
| 237 | 255 | } |
| 238 | 256 | |
| 239 | 257 | /** |
| 240 | - * Helper to return search conditions for entries (for complexity reduction) | |
| 241 | - * | |
| 258 | + * Override addFilterClauses to use EntryQueryHelper for filter WHERE clause construction. | |
| 242 | 259 | * @param array<string, mixed>|null $params |
| 243 | - * @return array<string> | |
| 244 | 260 | */ |
| 245 | - protected function getEntrySearchConditions(?array $params = null): array | |
| 261 | + protected function addFilterClauses(?array $params, array &$whereClauses, array &$queryParams): void | |
| 246 | 262 | { |
| 247 | - $conditions = [ | |
| 248 | - 'e.id LIKE %s', | |
| 249 | - 'e.formId LIKE %s', | |
| 250 | - 'f.name LIKE %s', | |
| 251 | - ]; | |
| 252 | - // Only include fieldValue if searchFieldValue is true (default true for BC) | |
| 253 | - if (!isset($params['searchFieldValue']) || $params['searchFieldValue']) { | |
| 254 | - $conditions[] = 'eft.fieldValue LIKE %s'; | |
| 263 | + $filterableColumns = $this->getFilterableColumns(); | |
| 264 | + $filterResult = EntryQueryHelper::buildFilterWhereClause($params, $filterableColumns); | |
| 265 | + if (!empty($filterResult['where'])) { | |
| 266 | + $whereClauses = array_merge($whereClauses, $filterResult['where']); | |
| 267 | + // Ensure all values are strings | |
| 268 | + $queryParams = array_merge($queryParams, array_map('strval', $filterResult['params'])); | |
| 255 | 269 | } |
| 256 | - return $conditions; | |
| 257 | - } | |
| 258 | 270 | |
| 259 | - /** | |
| 260 | - * Override addFilterClauses to prefix columns with the correct alias (e.g., e.) | |
| 261 | - * so that dynamic filtering works with JOINs and aliases. | |
| 262 | - */ | |
| 263 | - protected function addFilterClauses(?array $params, array &$whereClauses, array &$queryParams): void | |
| 264 | - { | |
| 265 | - if (!empty($params['filters'])) { | |
| 266 | - $filterableColumns = $this->getFilterableColumns(); | |
| 267 | - foreach ($params['filters'] as $key => $value) { | |
| 268 | - if (in_array($key, $filterableColumns, true) && $value !== null && $value !== '') { | |
| 269 | - // Prefix with e. for the entries table | |
| 270 | - $whereClauses[] = "e.{$key} = %s"; | |
| 271 | - $queryParams[] = sanitize_text_field($value); | |
| 272 | - } | |
| 273 | - } | |
| 274 | - } | |
| 271 | + VisibleFormIdsQueryFilter::apply($params, $whereClauses, $queryParams, 'e.formId'); | |
| 275 | 272 | } |
| 276 | 273 | |
| 277 | 274 | /** |
| 278 | 275 | * Get the columns that can be searched in the database (including virtual columns for search). |
| @@ -295,9 +292,9 @@ | ||
| 295 | 292 | * @return array<string> |
| 296 | 293 | */ |
| 297 | 294 | protected function getFilterableColumns(): array |
| 298 | 295 | { |
| 299 | - return ['starred', 'status', 'formId']; | |
| 296 | + return ['starred', 'status', 'formId', 'userId']; | |
| 300 | 297 | } |
| 301 | 298 | |
| 302 | 299 | /** |
| 303 | 300 | * Get sortable columns |
| @@ -305,9 +302,9 @@ | ||
| 305 | 302 | * @return array<string> |
| 306 | 303 | */ |
| 307 | 304 | protected function getSortableColumns(): array |
| 308 | 305 | { |
| 309 | - return ['id', 'dateCreated']; | |
| 306 | + return ['id', 'dateCreated', 'formName']; | |
| 310 | 307 | } |
| 311 | 308 | |
| 312 | 309 | /** |
| 313 | 310 | * Get the date column |
| @@ -322,8 +319,9 @@ | ||
| 322 | 319 | /** |
| 323 | 320 | * @param int $entryId |
| 324 | 321 | * |
| 325 | 322 | * @return bool |
| 323 | + * @throws QueryExecutionException | |
| 326 | 324 | */ |
| 327 | 325 | public function exists(int $entryId): bool |
| 328 | 326 | { |
| 329 | 327 | $query = $this->wpdb->prepare( |
| @@ -330,11 +328,15 @@ | ||
| 330 | 328 | "SELECT COUNT(*) FROM {$this->table} WHERE id = %d", |
| 331 | 329 | $entryId |
| 332 | 330 | ); |
| 333 | 331 | |
| 334 | - $count = (int) $this->wpdb->get_var($query); | |
| 335 | - | |
| 336 | - return $count > 0; | |
| 332 | + $count = $this->wpdb->get_var($query); | |
| 333 | + if ($count === false) { | |
| 334 | + throw new QueryExecutionException( | |
| 335 | + BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__ | |
| 336 | + ); | |
| 337 | + } | |
| 338 | + return (int)$count > 0; | |
| 337 | 339 | } |
| 338 | 340 | |
| 339 | 341 | /** |
| 340 | 342 | * Get the count of entries for a specific form. |
| @@ -340,19 +342,21 @@ | ||
| 340 | 342 | * Get the count of entries for a specific form. |
| 341 | 343 | * |
| 342 | 344 | * @param int $formId |
| 343 | 345 | * @return int |
| 346 | + * @throws QueryExecutionException | |
| 344 | 347 | */ |
| 345 | 348 | public function getCountByFormId(int $formId): int |
| 346 | 349 | { |
| 347 | - $query = $this->wpdb->prepare( | |
| 348 | - "SELECT COUNT(*) FROM {$this->table} WHERE formId = %d", | |
| 349 | - $formId | |
| 350 | - ); | |
| 351 | - | |
| 352 | - $count = (int) $this->wpdb->get_var($query); | |
| 353 | - | |
| 354 | - return $count; | |
| 350 | + $queryData = EntryQueryHelper::getCountByFormIdQuery($this->table, $formId); | |
| 351 | + $query = $this->wpdb->prepare($queryData['sql'], $queryData['params']); | |
| 352 | + $count = $this->wpdb->get_var($query); | |
| 353 | + if ($count === null) { | |
| 354 | + throw new QueryExecutionException( | |
| 355 | + BackendStrings::getExceptionStrings()['unable_find_by_id'] . __CLASS__ | |
| 356 | + ); | |
| 357 | + } | |
| 358 | + return (int)$count; | |
| 355 | 359 | } |
| 356 | 360 | |
| 357 | 361 | /** |
| 358 | 362 | * Get the count of entries for the filter dropdown. |
| @@ -358,28 +362,28 @@ | ||
| 358 | 362 | * Get the count of entries for the filter dropdown. |
| 359 | 363 | * |
| 360 | 364 | * @param array<string, mixed>|null $params |
| 361 | 365 | * @return array<string, int> |
| 366 | + * @throws QueryExecutionException | |
| 362 | 367 | */ |
| 363 | 368 | public function getFilterCount(?array $params = null): array |
| 364 | 369 | { |
| 365 | - $where = ''; | |
| 366 | - $queryParams = []; | |
| 367 | - if (!empty($params['filters']['formId'])) { | |
| 368 | - $where = 'WHERE formId = %d'; | |
| 369 | - $queryParams[] = (int)$params['filters']['formId']; | |
| 370 | + $queryData = EntryQueryHelper::getFilterCountQuery($this->table, $params); | |
| 371 | + $result = null; | |
| 372 | + if (!empty($queryData['params'])) { | |
| 373 | + $result = $this->wpdb->get_row( | |
| 374 | + $this->wpdb->prepare($queryData['sql'], ...$queryData['params']), | |
| 375 | + ARRAY_A | |
| 376 | + ); | |
| 370 | 377 | } |
| 371 | - $sql = "SELECT | |
| 372 | - SUM(status = 'read') as readTrueCount, | |
| 373 | - SUM(status = 'unread') as readFalseCount, | |
| 374 | - SUM(starred = 1) as starredTrueCount, | |
| 375 | - SUM(starred = 0) as starredFalseCount | |
| 376 | - FROM {$this->table} $where"; | |
| 377 | - $result = $this->wpdb->get_row( | |
| 378 | - $queryParams ? $this->wpdb->prepare($sql, ...$queryParams) : $sql, | |
| 379 | - ARRAY_A | |
| 380 | - ); | |
| 381 | - // Convert all values to integers and provide defaults if query returns null | |
| 378 | + if ($result === null) { | |
| 379 | + $result = $this->wpdb->get_row($queryData['sql'], ARRAY_A); | |
| 380 | + } | |
| 381 | + if ($result === null) { | |
| 382 | + throw new QueryExecutionException( | |
| 383 | + BackendStrings::getExceptionStrings()['unable_search_entries'] . __CLASS__ | |
| 384 | + ); | |
| 385 | + } | |
| 382 | 386 | return array_map('intval', $result ?: [ |
| 383 | 387 | 'readTrueCount' => 0, |
| 384 | 388 | 'readFalseCount' => 0, |
| 385 | 389 | 'starredTrueCount' => 0, |
| @@ -396,34 +400,21 @@ | ||
| 396 | 400 | * @throws QueryExecutionException|InvalidArgumentException |
| 397 | 401 | */ |
| 398 | 402 | public function getEntryFields(array $entries): array |
| 399 | 403 | { |
| 400 | - if (empty($entries)) { | |
| 404 | + $queryData = EntryQueryHelper::getEntryFieldsQuery($entries); | |
| 405 | + if (empty($queryData['sql'])) { | |
| 401 | 406 | return []; |
| 402 | 407 | } |
| 403 | - | |
| 404 | - // Extract entry IDs from the entries array | |
| 405 | - $entryIds = array_column($entries, 'id'); | |
| 406 | - | |
| 407 | - // Prepare placeholders for the query | |
| 408 | - $placeholders = implode(',', array_fill(0, count($entryIds), '%d')); | |
| 409 | - $entryFieldsTable = EntryFieldsTable::getTableName(); | |
| 410 | - | |
| 411 | - // Query to fetch fields for the given entry IDs | |
| 412 | - $query = "SELECT * FROM {$entryFieldsTable} WHERE entryId IN ($placeholders)"; | |
| 413 | - | |
| 414 | - // Execute the query with the entry IDs as parameters | |
| 415 | 408 | $results = $this->wpdb->get_results( |
| 416 | - $this->wpdb->prepare($query, $entryIds), | |
| 409 | + $this->wpdb->prepare($queryData['sql'], $queryData['params']), | |
| 417 | 410 | ARRAY_A |
| 418 | 411 | ); |
| 419 | - | |
| 420 | - if ($results === false) { | |
| 412 | + if ($results === null) { | |
| 421 | 413 | throw new QueryExecutionException( |
| 422 | 414 | BackendStrings::getExceptionStrings()['unable_get_entry_fields'] . __CLASS__ |
| 423 | 415 | ); |
| 424 | 416 | } |
| 425 | - | |
| 426 | 417 | return $results; |
| 427 | 418 | } |
| 428 | 419 | |
| 429 | 420 | /** |
| @@ -430,30 +421,59 @@ | ||
| 430 | 421 | * Get the count of entries for multiple form IDs. |
| 431 | 422 | * |
| 432 | 423 | * @param int[] $formIds |
| 433 | 424 | * @return array<int, int> formId => count |
| 425 | + * @throws QueryExecutionException | |
| 434 | 426 | * @throws InvalidArgumentException |
| 435 | 427 | */ |
| 436 | 428 | public function getEntryCountByFormIds(array $formIds): array |
| 437 | 429 | { |
| 438 | - if (empty($formIds)) { | |
| 430 | + $queryData = EntryQueryHelper::getEntryCountByFormIdsQuery($formIds); | |
| 431 | + if (empty($queryData['sql'])) { | |
| 439 | 432 | return []; |
| 440 | 433 | } |
| 441 | - $formIds = array_map('intval', $formIds); | |
| 442 | - $placeholders = implode(',', array_fill(0, count($formIds), '%d')); | |
| 443 | - $tableName = EntriesTable::getTableName(); | |
| 444 | - $query = "SELECT formId, COUNT(*) as count FROM {$tableName} WHERE formId IN ($placeholders) GROUP BY formId"; | |
| 445 | - $results = $this->wpdb->get_results($this->wpdb->prepare($query, $formIds), ARRAY_A); | |
| 434 | + $results = $this->wpdb->get_results( | |
| 435 | + $this->wpdb->prepare($queryData['sql'], $queryData['params']), | |
| 436 | + ARRAY_A | |
| 437 | + ); | |
| 438 | + if ($results === null) { | |
| 439 | + throw new QueryExecutionException( | |
| 440 | + BackendStrings::getExceptionStrings()['unable_search_entries'] . __CLASS__ | |
| 441 | + ); | |
| 442 | + } | |
| 446 | 443 | $counts = []; |
| 447 | 444 | foreach ($results as $row) { |
| 448 | 445 | $counts[(int)$row['formId']] = (int)$row['count']; |
| 449 | 446 | } |
| 450 | - | |
| 451 | - // Ensure all requested IDs are present in the result (default to 0) | |
| 452 | - foreach ($formIds as $id) { | |
| 447 | + foreach ($queryData['formIds'] as $id) { | |
| 453 | 448 | if (!isset($counts[$id])) { |
| 454 | 449 | $counts[$id] = 0; |
| 455 | 450 | } |
| 456 | 451 | } |
| 457 | 452 | return $counts; |
| 453 | + } | |
| 454 | + | |
| 455 | + /** | |
| 456 | + * Resolve owning form IDs for the given entry IDs in a single query. | |
| 457 | + * | |
| 458 | + * @param int[] $entryIds | |
| 459 | + * @return array<int, int> entryId => formId | |
| 460 | + * @throws QueryExecutionException | |
| 461 | + */ | |
| 462 | + public function getFormIdsByEntryIds(array $entryIds): array | |
| 463 | + { | |
| 464 | + return EntryQueryHelper::fetchFormIdsByEntryIds($this->wpdb, $entryIds); | |
| 465 | + } | |
| 466 | + | |
| 467 | + /** | |
| 468 | + * Get allowed columns for bulk update operations | |
| 469 | + * | |
| 470 | + * @return string[] | |
| 471 | + */ | |
| 472 | + protected function getAllowedBulkUpdateColumns(): array | |
| 473 | + { | |
| 474 | + return [ | |
| 475 | + self::COLUMN_STARRED, | |
| 476 | + self::COLUMN_STATUS, | |
| 477 | + ]; | |
| 458 | 478 | } |
| 459 | 479 | } |