← All changes
|
app/Repositories/RecurringAvailabilityRepository.php
+59
-6
3.0.4
→
3.0.16
View file →
| @@ -79,8 +79,46 @@ | ||
| 79 | 79 | return array_map([$this, 'hydrateRule'], $results ?: []); |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | /** |
| 83 | + * Find all rules matching ANY of the given trip IDs (batched | |
| 84 | + * counterpart of {@see self::findByTripId()}). Used by callers like | |
| 85 | + * {@see \Yatra\Repositories\DestinationRepository::computeStartingPriceForTripIds()} | |
| 86 | + * that previously issued one query per trip and got N+1 amplification. | |
| 87 | + * | |
| 88 | + * Currently supports just the `status` filter — that's all the | |
| 89 | + * batched callers need; ORDER and pagination are intentionally | |
| 90 | + * dropped because the caller folds the rows in PHP. | |
| 91 | + * | |
| 92 | + * @param list<int> $tripIds | |
| 93 | + */ | |
| 94 | + public function findByTripIds(array $tripIds, array $filters = []): array | |
| 95 | + { | |
| 96 | + $tripIds = array_values(array_unique(array_filter(array_map('intval', $tripIds), static fn (int $id): bool => $id > 0))); | |
| 97 | + if ($tripIds === []) { | |
| 98 | + return []; | |
| 99 | + } | |
| 100 | + | |
| 101 | + $table = esc_sql($this->table); | |
| 102 | + $placeholders = implode(',', array_fill(0, count($tripIds), '%d')); | |
| 103 | + $where = ["trip_id IN ({$placeholders})"]; | |
| 104 | + $params = $tripIds; | |
| 105 | + | |
| 106 | + if (!empty($filters['status']) && $filters['status'] !== 'all') { | |
| 107 | + $where[] = 'status = %s'; | |
| 108 | + $params[] = (string) $filters['status']; | |
| 109 | + } | |
| 110 | + | |
| 111 | + $query = "SELECT * FROM `{$table}` WHERE " . implode(' AND ', $where); | |
| 112 | + | |
| 113 | + $results = $this->wpdb->get_results( | |
| 114 | + $this->wpdb->prepare($query, ...$params) | |
| 115 | + ); | |
| 116 | + | |
| 117 | + return array_map([$this, 'hydrateRule'], $results ?: []); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 83 | 121 | * Count rules by trip ID |
| 84 | 122 | */ |
| 85 | 123 | public function countByTripId(int $tripId, array $filters = []): int |
| 86 | 124 | { |
| @@ -185,23 +223,38 @@ | ||
| 185 | 223 | */ |
| 186 | 224 | public function findActiveRulesForDate(int $tripId, string $date): array |
| 187 | 225 | { |
| 188 | 226 | $table = esc_sql($this->table); |
| 189 | - | |
| 227 | + | |
| 228 | + // Date-only compare: start_date/end_date are DATE columns, so a datetime | |
| 229 | + // input would break the `end_date >= %s` boundary (DATE treated as midnight). | |
| 230 | + if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $date, $m)) { | |
| 231 | + $date = $m[1]; | |
| 232 | + } | |
| 233 | + | |
| 234 | + // Callers (notably CapacityService) take the FIRST row as the winning | |
| 235 | + // rule, so the ordering must be total — not just `priority DESC`. | |
| 236 | + // `priority` is not exposed in the rule editor, so every rule carries the | |
| 237 | + // same default and overlapping rules tied, leaving the winner to MySQL's | |
| 238 | + // arbitrary row order. A trip with an older wide rule (e.g. 25 seats) plus | |
| 239 | + // a newer, narrower one (e.g. 1 seat for a private group) could therefore | |
| 240 | + // resolve to the wrong capacity and silently fall back to the trip default. | |
| 241 | + // Break ties by most-recently-created, matching the ordering this same | |
| 242 | + // repository already uses for rule listings. | |
| 190 | 243 | $query = $this->wpdb->prepare( |
| 191 | - "SELECT * FROM `{$table}` | |
| 192 | - WHERE trip_id = %d | |
| 244 | + "SELECT * FROM `{$table}` | |
| 245 | + WHERE trip_id = %d | |
| 193 | 246 | AND status = 'active' |
| 194 | 247 | AND start_date <= %s |
| 195 | 248 | AND (end_date IS NULL OR end_date >= %s) |
| 196 | - ORDER BY priority DESC", | |
| 249 | + ORDER BY priority DESC, created_at DESC, id DESC", | |
| 197 | 250 | $tripId, |
| 198 | 251 | $date, |
| 199 | 252 | $date |
| 200 | 253 | ); |
| 201 | - | |
| 254 | + | |
| 202 | 255 | $results = $this->wpdb->get_results($query); |
| 203 | - | |
| 256 | + | |
| 204 | 257 | return array_map([$this, 'hydrateRule'], $results ?: []); |
| 205 | 258 | } |
| 206 | 259 | |
| 207 | 260 | /** |