PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.7
Yatra – Travel Booking & Tour Operator Software v3.0.2.7
3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 2.0.11 All 82 releases
yatra / app / Controllers / CacheController.php

CacheController.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.7, at app/Controllers/CacheController.php

593 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\Controllers;
6
7 use WP_REST_Request;
8 use WP_REST_Response;
9 use WP_Error;
10 use Yatra\Utils\Logger;
11 use Yatra\Utils\Cache;
12
13 /**
14 * Cache Management Controller
15 * Handles cache operations for admin interface
16 */
17 class CacheController extends BaseController
18 {
19 /**
20 * Register REST API routes
21 */
22 public function register_routes(): void
23 {
24 register_rest_route('yatra/v1', '/cache/stats', [
25 [
26 'methods' => \WP_REST_Server::READABLE,
27 'callback' => [$this, 'getStats'],
28 'permission_callback' => [$this, 'checkPermissions']
29 ]
30 ]);
31
32 register_rest_route('yatra/v1', '/cache/view', [
33 [
34 'methods' => \WP_REST_Server::READABLE,
35 'callback' => [$this, 'getAllCacheData'],
36 'permission_callback' => [$this, 'checkPermissions']
37 ]
38 ]);
39
40 register_rest_route('yatra/v1', '/cache/status', [
41 [
42 'methods' => \WP_REST_Server::READABLE,
43 'callback' => [$this, 'getCacheStatus'],
44 'permission_callback' => [$this, 'checkPermissions']
45 ]
46 ]);
47
48 register_rest_route('yatra/v1', '/cache/enable', [
49 [
50 'methods' => \WP_REST_Server::EDITABLE,
51 'callback' => [$this, 'enableCache'],
52 'permission_callback' => [$this, 'checkPermissions']
53 ]
54 ]);
55
56 register_rest_route('yatra/v1', '/cache/disable', [
57 [
58 'methods' => \WP_REST_Server::EDITABLE,
59 'callback' => [$this, 'disableCache'],
60 'permission_callback' => [$this, 'checkPermissions']
61 ]
62 ]);
63
64 register_rest_route('yatra/v1', '/cache/clear-item', [
65 [
66 'methods' => \WP_REST_Server::DELETABLE,
67 'callback' => [$this, 'clearCacheItem'],
68 'permission_callback' => [$this, 'checkPermissions']
69 ]
70 ]);
71
72 register_rest_route('yatra/v1', '/cache/clear-all', [
73 [
74 'methods' => \WP_REST_Server::DELETABLE,
75 'callback' => [$this, 'clearAll'],
76 'permission_callback' => [$this, 'checkPermissions']
77 ]
78 ]);
79
80 register_rest_route('yatra/v1', '/cache/clear-pattern', [
81 [
82 'methods' => \WP_REST_Server::DELETABLE,
83 'callback' => [$this, 'clearByPattern'],
84 'permission_callback' => [$this, 'checkPermissions']
85 ]
86 ]);
87
88 register_rest_route('yatra/v1', '/cache/toggle', [
89 [
90 'methods' => \WP_REST_Server::CREATABLE,
91 'callback' => [$this, 'toggleCache'],
92 'permission_callback' => [$this, 'checkPermissions']
93 ]
94 ]);
95
96 register_rest_route('yatra/v1', '/cache/warm', [
97 [
98 'methods' => \WP_REST_Server::CREATABLE,
99 'callback' => [$this, 'warmCache'],
100 'permission_callback' => [$this, 'checkPermissions']
101 ]
102 ]);
103 }
104
105 /**
106 * Register REST API routes (alias for compatibility)
107 */
108 public static function registerRoutes(): void
109 {
110 $instance = new self();
111 $instance->register_routes();
112 }
113
114 /**
115 * Check permissions for cache operations
116 */
117 public function checkPermissions(): bool
118 {
119 return current_user_can('manage_options');
120 }
121
122 /**
123 * Get cache statistics
124 */
125 public function getStats()
126 {
127 try {
128 $metrics = get_option('yatra_cache_metrics', []);
129 $status = \Yatra\Utils\Cache::getStatus();
130 $stats = [
131 'total_operations' => count($metrics),
132 'cache_hits' => 0,
133 'cache_misses' => 0,
134 'avg_execution_time' => 0,
135 'cache_enabled' => $status['cache_enabled'],
136 'cache_effective' => $status['effective_status'],
137 'cache_reason_disabled' => $status['reason_disabled'],
138 'cache_backend_available' => function_exists('get_transient'),
139 'recent_operations' => array_slice($metrics, -10)
140 ];
141
142 if (!empty($metrics)) {
143 $totalTime = 0;
144 foreach ($metrics as $metric) {
145 if ($metric['cache_used']) {
146 $stats['cache_hits']++;
147 } else {
148 $stats['cache_misses']++;
149 }
150 $totalTime += $metric['execution_time'];
151 }
152 $stats['avg_execution_time'] = round($totalTime / count($metrics), 2);
153 $stats['hit_rate'] = $stats['total_operations'] > 0
154 ? round(($stats['cache_hits'] / $stats['total_operations']) * 100, 2)
155 : 0;
156 }
157
158 return $this->success_response($stats);
159
160 } catch (\Exception $e) {
161 Logger::error('Failed to get cache statistics', ['error' => $e->getMessage()]);
162 return $this->error_response('Failed to get cache statistics');
163 }
164 }
165
166 /**
167 * Get all cache data for viewing
168 */
169 public function getAllCacheData()
170 {
171 try {
172 $cacheData = [];
173
174 // Get ALL Yatra-related transients
175 global $wpdb;
176
177 // Debug: Check if any transients exist at all
178 $allTransients = $wpdb->get_results(
179 "SELECT option_name, option_value, option_id
180 FROM {$wpdb->options}
181 WHERE option_name LIKE '_transient_%'
182 ORDER BY option_name LIMIT 10"
183 );
184
185 Logger::debug('All transients in database', ['count' => count($allTransients)]);
186 if (!empty($allTransients)) {
187 Logger::debug('Sample transients', array_slice($allTransients, 0, 3));
188 }
189
190 // Get Yatra-specific transients (both free and pro)
191 $transients = $wpdb->get_results(
192 "SELECT option_name, option_value, option_id
193 FROM {$wpdb->options}
194 WHERE (option_name LIKE '_transient_yatra_%' OR option_name LIKE '_transient_yatra_pro_%')
195 ORDER BY option_name"
196 );
197
198 // Debug: Log Yatra transients found
199 Logger::debug('Yatra transients found', ['count' => count($transients)]);
200 Logger::debug('Yatra transient names', array_column($transients, 'option_name'));
201
202 // Filter out timeout transients, keep only data transients
203 $transients = array_filter($transients, function($transient) {
204 return !strpos($transient->option_name, '_transient_timeout_');
205 });
206
207 Logger::debug('Yatra data transients after filtering', ['count' => count($transients)]);
208
209 foreach ($transients as $transient) {
210 $key = str_replace('_transient_', '', $transient->option_name);
211 $value = maybe_unserialize($transient->option_value);
212
213 // Get expiration time from timeout option
214 $timeoutOption = '_transient_timeout_' . $key;
215 $expiration = get_option($timeoutOption);
216 $expiresAt = $expiration ? date('Y-m-d H:i:s', (int)$expiration) : 'Never expires';
217
218 // Format value for better display
219 $displayValue = $this->formatCacheValue($value);
220
221 $cacheData[] = [
222 'key' => $key,
223 'type' => 'transient',
224 'value' => $displayValue,
225 'size' => strlen($transient->option_value),
226 'created_at' => current_time('mysql'),
227 'expires_at' => $expiresAt,
228 'option_id' => $transient->option_id
229 ];
230 }
231
232 // Get memory cache data
233 $memoryCache = Cache::getCacheStats();
234 if (!empty($memoryCache['memory_cache_size'])) {
235 $cacheData[] = [
236 'key' => 'memory_cache',
237 'type' => 'memory',
238 'value' => 'Memory cache data (' . $memoryCache['memory_cache_size'] . ' items)',
239 'size' => $memoryCache['memory_usage'] ?? 0,
240 'created_at' => current_time('mysql'),
241 'expires_at' => 'End of request',
242 'option_id' => null
243 ];
244 }
245
246 return $this->success_response([
247 'success' => true,
248 'message' => 'Cache data retrieved',
249 'data' => [
250 'cache_data' => $cacheData,
251 'total_items' => count($cacheData),
252 'total_size' => array_sum(array_column($cacheData, 'size'))
253 ]
254 ]);
255
256 } catch (\Exception $e) {
257 Logger::error('Failed to get cache data', ['error' => $e->getMessage()]);
258 return $this->error_response('Failed to get cache data');
259 }
260 }
261
262 /**
263 * Clear specific cache item
264 */
265 public function clearCacheItem(WP_REST_Request $request)
266 {
267 try {
268 $key = $request->get_param('key');
269 $type = $request->get_param('type');
270
271 if (empty($key)) {
272 return $this->error_response('Cache key is required');
273 }
274
275 $success = false;
276 $message = '';
277
278 switch ($type) {
279 case 'transient':
280 $success = delete_transient($key);
281 // Also delete the timeout entry
282 delete_option('_transient_timeout_' . $key);
283 $message = $success ? 'Transient cache cleared' : 'Failed to clear transient cache';
284 break;
285 case 'memory':
286 // Memory cache is handled by the Cache class
287 Cache::delete($key);
288 $success = true;
289 $message = 'Memory cache cleared';
290 break;
291 default:
292 // Try to clear from all available backends
293 Cache::delete($key);
294 $success = true;
295 $message = 'Cache cleared from all backends';
296 break;
297 }
298
299 if ($success) {
300 Logger::info("Cache item cleared", ['key' => $key, 'type' => $type]);
301 return $this->success_response([
302 'success' => true,
303 'message' => $message,
304 'data' => ['key' => $key, 'type' => $type]
305 ]);
306 } else {
307 return $this->error_response('Failed to clear cache item');
308 }
309
310 } catch (\Exception $e) {
311 Logger::error('Failed to clear cache item', ['error' => $e->getMessage()]);
312 return $this->error_response('Failed to clear cache item');
313 }
314 }
315
316 /**
317 * Get transient creation time
318 */
319 private function getTransientCreatedTime(string $optionName): string
320 {
321 global $wpdb;
322
323 $result = $wpdb->get_var($wpdb->prepare(
324 "SELECT option_added FROM {$wpdb->options} WHERE option_name = %s",
325 $optionName
326 ));
327
328 return $result ? date('Y-m-d H:i:s', strtotime($result)) : 'Unknown';
329 }
330
331 /**
332 * Get transient expiration time
333 */
334 private function getTransientExpirationTime(string $optionName): string
335 {
336 global $wpdb;
337
338 $timeoutKey = '_transient_timeout_' . str_replace('_transient_', '', $optionName);
339 $timeout = $wpdb->get_var($wpdb->prepare(
340 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s",
341 $timeoutKey
342 ));
343
344 return $timeout ? date('Y-m-d H:i:s', $timeout) : 'No expiration';
345 }
346
347 /**
348 * Clear all cache
349 */
350 public function clearAll()
351 {
352 try {
353 $startTime = microtime(true);
354
355 // Clear all Yatra cache
356 Cache::clearByPrefix('yatra_');
357
358 $executionTime = round((microtime(true) - $startTime) * 1000, 2);
359
360 Logger::info('All cache cleared', ['execution_time' => $executionTime]);
361
362 return $this->success_response([
363 'success' => true,
364 'message' => 'All cache cleared',
365 'data' => [
366 'execution_time' => $executionTime
367 ]
368 ]);
369
370 } catch (\Exception $e) {
371 Logger::error('Failed to clear all cache', ['error' => $e->getMessage()]);
372 return $this->error_response('Failed to clear all cache');
373 }
374 }
375
376 /**
377 * Clear cache by pattern
378 */
379 public function clearByPattern(WP_REST_Request $request)
380 {
381 try {
382 $pattern = $request->get_param('pattern');
383
384 if (empty($pattern)) {
385 return $this->error_response('Pattern is required');
386 }
387
388 $startTime = microtime(true);
389
390 // Clear cache by pattern
391 Cache::clearByPrefix($pattern);
392
393 $executionTime = round((microtime(true) - $startTime) * 1000, 2);
394
395 Logger::info('Cache cleared by pattern', [
396 'pattern' => $pattern,
397 'execution_time' => $executionTime
398 ]);
399
400 return $this->success_response([
401 'success' => true,
402 'message' => 'Cache cleared by pattern',
403 'data' => [
404 'pattern' => $pattern,
405 'execution_time' => $executionTime
406 ]
407 ]);
408
409 } catch (\Exception $e) {
410 Logger::error('Failed to clear cache by pattern', [
411 'pattern' => $pattern ?? 'unknown',
412 'error' => $e->getMessage()
413 ]);
414 return $this->error_response('Failed to clear cache by pattern');
415 }
416 }
417
418 /**
419 * Toggle cache enabled status
420 */
421 public function toggleCache(WP_REST_Request $request)
422 {
423 try {
424 $enabled = $request->get_param('enabled');
425 $enabled = filter_var($enabled, FILTER_VALIDATE_BOOLEAN);
426
427 update_option('yatra_cache_enabled', $enabled);
428
429 Logger::info('Cache status toggled', ['enabled' => $enabled]);
430
431 return $this->success_response([
432 'success' => true,
433 'message' => 'Cache status updated',
434 'data' => [
435 'cache_enabled' => $enabled
436 ]
437 ]);
438
439 } catch (\Exception $e) {
440 Logger::error('Failed to toggle cache status', ['error' => $e->getMessage()]);
441 return $this->error_response('Failed to toggle cache status');
442 }
443 }
444
445 /**
446 * Warm cache
447 */
448 public function warmCache()
449 {
450 try {
451 $startTime = microtime(true);
452 $warmed = [];
453
454 // Warm common cache patterns
455 $patterns = [
456 'yatra_frontend_attributes',
457 'yatra_filterable_attributes',
458 'trip_listing_filter_options',
459 ];
460
461 foreach ($patterns as $pattern) {
462 // Clear existing cache for this pattern
463 Cache::clearByPrefix($pattern);
464 $warmed[] = $pattern;
465 }
466
467 $executionTime = round((microtime(true) - $startTime) * 1000, 2);
468
469 Logger::info('Cache warmed', [
470 'warmed_patterns' => $warmed,
471 'execution_time' => $executionTime
472 ]);
473
474 return $this->success_response([
475 'success' => true,
476 'message' => 'Cache warmed',
477 'data' => [
478 'warmed_patterns' => $warmed,
479 'execution_time' => $executionTime
480 ]
481 ]);
482
483 } catch (\Exception $e) {
484 Logger::error('Failed to warm cache', ['error' => $e->getMessage()]);
485 return $this->error_response('Failed to warm cache');
486 }
487 }
488
489 /**
490 * Format cache value for better display
491 */
492 private function formatCacheValue($value): string
493 {
494 // Return actual data as JSON for frontend to display
495 if (is_array($value) || is_object($value)) {
496 return json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
497 }
498
499 if (is_bool($value)) {
500 return $value ? 'true' : 'false';
501 }
502
503 if (is_null($value)) {
504 return 'null';
505 }
506
507 if (is_string($value)) {
508 // Return the actual string value
509 return $value;
510 }
511
512 if (is_numeric($value)) {
513 return (string) $value;
514 }
515
516 return 'Unknown type: ' . gettype($value);
517 }
518
519 /**
520 * Get cache status
521 */
522 public function getCacheStatus()
523 {
524 try {
525 $status = \Yatra\Utils\Cache::getStatus();
526
527 Logger::info('Cache status retrieved', $status);
528
529 return $this->success_response([
530 'success' => true,
531 'message' => 'Cache status retrieved',
532 'data' => $status
533 ]);
534
535 } catch (\Exception $e) {
536 Logger::error('Failed to get cache status', ['error' => $e->getMessage()]);
537 return $this->error_response('Failed to get cache status');
538 }
539 }
540
541 /**
542 * Enable cache
543 */
544 public function enableCache()
545 {
546 try {
547 $success = \Yatra\Utils\Cache::enableForTesting();
548
549 if ($success) {
550 Logger::info('Cache enabled successfully');
551 return $this->success_response([
552 'success' => true,
553 'message' => 'Cache enabled successfully',
554 'data' => ['cache_enabled' => true]
555 ]);
556 } else {
557 return $this->error_response('Failed to enable cache');
558 }
559
560 } catch (\Exception $e) {
561 Logger::error('Failed to enable cache', ['error' => $e->getMessage()]);
562 return $this->error_response('Failed to enable cache');
563 }
564 }
565
566 /**
567 * Disable cache
568 */
569 public function disableCache()
570 {
571 try {
572 $success = \Yatra\Utils\Cache::disableForTesting();
573
574 if ($success) {
575 Logger::info('Cache disabled successfully');
576 return $this->success_response([
577 'success' => true,
578 'message' => 'Cache disabled successfully',
579 'data' => ['cache_enabled' => false]
580 ]);
581 } else {
582 return $this->error_response('Failed to disable cache');
583 }
584
585 } catch (\Exception $e) {
586 Logger::error('Failed to disable cache', ['error' => $e->getMessage()]);
587 return $this->error_response('Failed to disable cache');
588 }
589 }
590
591
592 }
593