| @@ -4,8 +4,9 @@ | ||
| 4 | 4 | |
| 5 | 5 | namespace Yatra\Repositories; |
| 6 | 6 | |
| 7 | 7 | use Yatra\Constants\ClassificationTypes; |
| 8 | +use Yatra\Utils\Cache; | |
| 8 | 9 | |
| 9 | 10 | /** |
| 10 | 11 | * Trip Category Repository |
| 11 | 12 | * Handles database operations for trip categories |
| @@ -171,16 +172,51 @@ | ||
| 171 | 172 | |
| 172 | 173 | /** |
| 173 | 174 | * Get published categories with trip counts, ratings, and pricing stats |
| 174 | 175 | */ |
| 176 | + /** | |
| 177 | + * Wipe listing caches when a trip-category row is written so | |
| 178 | + * {@see self::getPublishedWithTripCounts()} doesn't serve stale | |
| 179 | + * aggregates. {@see \Yatra\Hooks\CacheHooks} only watches trips / | |
| 180 | + * activities / destinations / bookings — category writes have no | |
| 181 | + * corresponding domain action. | |
| 182 | + */ | |
| 183 | + protected function afterWrite(string $operation, int $id, array $context = []): void | |
| 184 | + { | |
| 185 | + Cache::invalidateListingCaches(); | |
| 186 | + } | |
| 187 | + | |
| 175 | 188 | public function getPublishedWithTripCounts(): array |
| 176 | 189 | { |
| 190 | + // Cache the full payload. /trip-categories used to run the | |
| 191 | + // GROUP BY aggregate plus one MIN-price SELECT per category on | |
| 192 | + // every request. Cache key uses the `trip_listing_` prefix that | |
| 193 | + // {@see \Yatra\Utils\Cache::invalidateListingCaches()} clears on | |
| 194 | + // every trip / category write (the latter via this class's | |
| 195 | + // afterWrite override), so visitors always see current data | |
| 196 | + // after admin edits. | |
| 197 | + return $this->cacheQueryResult( | |
| 198 | + 'trip_listing_categories_with_counts_v2', | |
| 199 | + function (): array { | |
| 200 | + return $this->fetchPublishedWithTripCounts(); | |
| 201 | + }, | |
| 202 | + Cache::DURATION_LISTINGS | |
| 203 | + ); | |
| 204 | + } | |
| 205 | + | |
| 206 | + /** | |
| 207 | + * Uncached worker for {@see self::getPublishedWithTripCounts()}. | |
| 208 | + * | |
| 209 | + * @return array<int, \stdClass> | |
| 210 | + */ | |
| 211 | + private function fetchPublishedWithTripCounts(): array | |
| 212 | + { | |
| 177 | 213 | $table = esc_sql($this->table); |
| 178 | - | |
| 214 | + | |
| 179 | 215 | // Use TripRepository for trips table |
| 180 | 216 | $tripRepository = new \Yatra\Repositories\TripRepository(); |
| 181 | 217 | $trip_table = esc_sql($tripRepository->getTableName()); |
| 182 | - | |
| 218 | + | |
| 183 | 219 | // Use TripClassificationsTable for trip-category relationships |
| 184 | 220 | $trip_cat_table = esc_sql(\Yatra\Database\Tables\TripClassificationsTable::getTableName()); |
| 185 | 221 | $reviews_table = esc_sql(\Yatra\Database\Tables\ReviewsTable::getTableName()); |
| 186 | 222 | |
| @@ -186,9 +222,9 @@ | ||
| 186 | 222 | |
| 187 | 223 | // TripClassificationsTable uses classification_id + classification_type (not category_id). |
| 188 | 224 | // ClassificationsTable holds all taxonomy rows — restrict to type = category. |
| 189 | 225 | $query = $this->wpdb->prepare( |
| 190 | - "SELECT c.*, | |
| 226 | + "SELECT c.*, | |
| 191 | 227 | COUNT(DISTINCT tc.trip_id) AS trips_count, |
| 192 | 228 | COALESCE(AVG(r.rating), 0) AS avg_rating, |
| 193 | 229 | GROUP_CONCAT(DISTINCT tc.trip_id) AS trip_ids |
| 194 | 230 | FROM `{$table}` c |