PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.3
Yatra – Travel Booking & Tour Operator Software v3.0.3
3.0.15 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 All 83 releases
yatra / app / Core / Routing / PrettyRouteMatcher.php

PrettyRouteMatcher.php in Yatra – Travel Booking & Tour Operator Software 3.0.3, at app/Core/Routing/PrettyRouteMatcher.php

224 lines 7.0 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\Core\Routing;
6
7 use Yatra\Services\SettingsService;
8
9 /**
10 * Matches request paths served as path-based (pretty) URLs.
11 * Used for: plain-permalink mode 404 when path looks like a plugin pretty URL, and by {@see Router}.
12 */
13 final class PrettyRouteMatcher
14 {
15 /**
16 * @return array<string, mixed>|null Same shape as {@see Router} route_data
17 */
18 public static function match(string $path): ?array
19 {
20 $path = trim($path, '/');
21
22 // 1. Email verification
23 if (preg_match('/^yatra-verify-email\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
24 return [
25 'type' => 'email_verification',
26 'token' => $matches[1],
27 ];
28 }
29
30 // 2. Account page
31 $account_base = SettingsService::getAccountBase();
32 $account_route = self::matchAccountRoute($path, $account_base);
33 if ($account_route !== null) {
34 return $account_route;
35 }
36
37 // 3. Trip archive pagination: {trip_base}/page/{n}
38 $trip_base = SettingsService::getTripBase();
39 if (preg_match('/^' . preg_quote($trip_base, '/') . '\/page\/(\d+)\/?$/', $path, $matches)) {
40 return [
41 'type' => 'listing',
42 'listing_type' => 'trip',
43 'base' => $trip_base,
44 'paged' => max(1, (int) $matches[1]),
45 ];
46 }
47
48 // 5. Single trip
49 if (preg_match('/^' . preg_quote($trip_base, '/') . '\/([^\/]+)\/?$/', $path, $matches)) {
50 if ($matches[1] !== 'page') {
51 return [
52 'type' => 'trip',
53 'slug' => $matches[1],
54 'base' => $trip_base,
55 ];
56 }
57 }
58
59 // 6. Taxonomy (pagination before single slug)
60 $bases = [
61 'destination' => SettingsService::getString('destination_base', 'destination'),
62 'activity' => SettingsService::getString('activity_base', 'activity'),
63 'category' => SettingsService::getString('trip_category_base', 'trip-category'),
64 ];
65
66 foreach ($bases as $type => $base) {
67 if (preg_match('/^' . preg_quote($base, '/') . '\/([^\/]+)\/page\/(\d+)\/?$/', $path, $matches)) {
68 return [
69 'type' => 'taxonomy',
70 'taxonomy_type' => $type,
71 'slug' => $matches[1],
72 'base' => $base,
73 'paged' => max(1, (int) $matches[2]),
74 ];
75 }
76 }
77
78 foreach ($bases as $type => $base) {
79 if (preg_match('/^' . preg_quote($base, '/') . '\/([^\/]+)\/?$/', $path, $matches)) {
80 return [
81 'type' => 'taxonomy',
82 'taxonomy_type' => $type,
83 'slug' => $matches[1],
84 'base' => $base,
85 ];
86 }
87 }
88
89 // 7. Listing roots
90 foreach ($bases as $type => $base) {
91 if ($path === $base) {
92 return [
93 'type' => 'listing',
94 'listing_type' => $type,
95 'base' => $base,
96 ];
97 }
98 }
99
100 if ($path === $trip_base) {
101 return [
102 'type' => 'listing',
103 'listing_type' => 'trip',
104 'base' => $trip_base,
105 ];
106 }
107
108 // 8. Booking confirmation (pageless: /{booking_base}/confirmation/{ref}/ + legacy slug)
109 $booking_base = SettingsService::getBookingBase();
110 if (preg_match('/^' . preg_quote($booking_base, '/') . '\/confirmation\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
111 return [
112 'type' => 'booking_confirmation',
113 'confirmation_id' => $matches[1],
114 ];
115 }
116
117 if (preg_match('/^booking-confirmation\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
118 return [
119 'type' => 'booking_confirmation',
120 'confirmation_id' => $matches[1],
121 ];
122 }
123
124 // 9. Remaining checkout (rewrite) and legacy checkout/ path
125 if (preg_match('/^remaining-checkout\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
126 return [
127 'type' => 'checkout',
128 'token' => $matches[1],
129 ];
130 }
131
132 if (preg_match('/^checkout\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
133 return [
134 'type' => 'checkout',
135 'token' => $matches[1],
136 ];
137 }
138
139 // 10. Booking hub / trip booking
140 if (!SettingsService::useCustomBookingPage()) {
141 if (preg_match('/^' . preg_quote($booking_base, '/') . '\/([^\/]+)\/?$/', $path, $matches)) {
142 return [
143 'type' => 'booking',
144 'page' => 'main',
145 'base' => $booking_base,
146 'trip' => $matches[1],
147 ];
148 }
149 if ($path === $booking_base) {
150 return [
151 'type' => 'booking',
152 'page' => 'main',
153 'base' => $booking_base,
154 ];
155 }
156 }
157
158 return null;
159 }
160
161 /**
162 * @return array{type: string, page: string, base: string}|null
163 */
164 private static function matchAccountRoute(string $path, string $account_base): ?array
165 {
166 $path_trim = rtrim($path, '/');
167 $base_trim = rtrim($account_base, '/');
168
169 if ($path_trim === $base_trim) {
170 $tab = isset($_GET['tab']) ? sanitize_key((string) $_GET['tab']) : '';
171
172 return [
173 'type' => 'account',
174 'page' => self::accountQueryTabToPage($tab),
175 'base' => $account_base,
176 ];
177 }
178
179 $quoted = preg_quote($account_base, '/');
180 if (preg_match('/^' . $quoted . '\/([^\/]+)/', $path, $m)) {
181 $page = self::accountPathSegmentToPage($m[1]);
182 if ($page === null) {
183 return null;
184 }
185
186 return [
187 'type' => 'account',
188 'page' => $page,
189 'base' => $account_base,
190 ];
191 }
192
193 return null;
194 }
195
196 private static function accountQueryTabToPage(string $tab): string
197 {
198 $allowed = ['dashboard', 'bookings', 'payments', 'documents', 'profile', 'saved-trips'];
199 if ($tab === '' || !in_array($tab, $allowed, true)) {
200 return 'dashboard';
201 }
202
203 return $tab;
204 }
205
206 private static function accountPathSegmentToPage(string $segment): ?string
207 {
208 $segment = sanitize_title($segment);
209 $map = [
210 'dashboard' => 'dashboard',
211 'profile' => 'profile',
212 'bookings' => 'bookings',
213 'payments' => 'payments',
214 'documents' => 'documents',
215 'support' => 'dashboard',
216 'saved-trips' => 'saved-trips',
217 'wishlist' => 'saved-trips',
218 'settings' => 'profile',
219 ];
220
221 return $map[$segment] ?? null;
222 }
223 }
224