| @@ -151,12 +151,46 @@ | ||
| 151 | 151 | /** |
| 152 | 152 | * Get published activities with trip counts and stats |
| 153 | 153 | * Uses the new ClassificationsTable and TripClassificationsTable |
| 154 | 154 | */ |
| 155 | + /** | |
| 156 | + * Wipe listing caches whenever an activity row is created / | |
| 157 | + * updated / deleted so {@see self::getPublishedWithTripCounts()} | |
| 158 | + * never serves stale aggregates. See the matching override in | |
| 159 | + * {@see DestinationRepository::afterWrite()} for the full reasoning | |
| 160 | + * — the existing `yatra_activity_*` CacheHooks listeners only fire | |
| 161 | + * when an action of that name is dispatched, and no caller does. | |
| 162 | + */ | |
| 163 | + protected function afterWrite(string $operation, int $id, array $context = []): void | |
| 164 | + { | |
| 165 | + Cache::invalidateListingCaches(); | |
| 166 | + } | |
| 167 | + | |
| 155 | 168 | public function getPublishedWithTripCounts(): array |
| 156 | 169 | { |
| 157 | - global $wpdb; | |
| 170 | + // Cache the aggregate so repeat visits skip the GROUP BY + | |
| 171 | + // per-activity MIN-price subquery. Cache key sits behind the | |
| 172 | + // `activity_listing_` prefix wiped by | |
| 173 | + // {@see \Yatra\Utils\Cache::invalidateListingCaches()}, which | |
| 174 | + // runs whenever an activity/trip row is written (via this | |
| 175 | + // class's afterWrite or {@see \Yatra\Hooks\CacheHooks} on trip | |
| 176 | + // writes). Stale data is impossible after admin edits. | |
| 177 | + return $this->cacheQueryResult( | |
| 178 | + 'activity_listing_with_trip_counts_v2', | |
| 179 | + function (): array { | |
| 180 | + return $this->fetchPublishedWithTripCounts(); | |
| 181 | + }, | |
| 182 | + Cache::DURATION_ACTIVITY_DATA | |
| 183 | + ); | |
| 184 | + } | |
| 158 | 185 | |
| 186 | + /** | |
| 187 | + * Uncached worker for {@see self::getPublishedWithTripCounts()}. | |
| 188 | + * | |
| 189 | + * @return array<int, \stdClass> | |
| 190 | + */ | |
| 191 | + private function fetchPublishedWithTripCounts(): array | |
| 192 | + { | |
| 159 | 193 | $actTable = esc_sql($this->table); |
| 160 | 194 | $relTable = TripClassificationsTable::getTableName(); |
| 161 | 195 | $tripsTable = TripsTable::getTableName(); |
| 162 | 196 | $reviewsTable = ReviewsTable::getTableName(); |
| @@ -175,15 +209,15 @@ | ||
| 175 | 209 | $statuses = ['active', 'publish']; |
| 176 | 210 | } |
| 177 | 211 | $statusIn = implode(',', array_fill(0, count($statuses), '%s')); |
| 178 | 212 | |
| 179 | - $sql = "SELECT a.*, | |
| 213 | + $sql = "SELECT a.*, | |
| 180 | 214 | COUNT(DISTINCT tc.trip_id) AS trips_count, |
| 181 | 215 | COALESCE(AVG(r.rating), 0) AS avg_rating, |
| 182 | 216 | GROUP_CONCAT(DISTINCT tc.trip_id) AS trip_ids |
| 183 | 217 | FROM `{$actTable}` a |
| 184 | 218 | LEFT JOIN `{$relTable}` tc |
| 185 | - ON tc.classification_id = a.id | |
| 219 | + ON tc.classification_id = a.id | |
| 186 | 220 | AND tc.classification_type = %s |
| 187 | 221 | LEFT JOIN `{$tripsTable}` t |
| 188 | 222 | ON t.id = tc.trip_id |
| 189 | 223 | LEFT JOIN `{$reviewsTable}` r |