PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.13
Yatra – Travel Booking & Tour Operator Software v3.0.13
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 / Services / FilterService.php

FilterService.php in Yatra – Travel Booking & Tour Operator Software 3.0.13, at app/Services/FilterService.php

429 lines 20.9 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\Services;
6
7 use Yatra\Services\DifficultyLevelService;
8 use Yatra\Services\TripCategoryService;
9 use Yatra\Services\DestinationService;
10 use Yatra\Services\ActivityService;
11 use Yatra\Database\Tables\TripsTable;
12
13 /**
14 * Filter Service
15 * Contains business logic for rendering individual filter components
16 */
17 class FilterService extends BaseService
18 {
19 /**
20 * Render price range filter component
21 *
22 * @param array $active_filters Current active filters
23 * @param array $options Filter options (min_price, max_price, step)
24 * @return string HTML output
25 */
26 public function renderPriceRangeFilter(array $active_filters = [], array $options = []): string
27 {
28 // Get price range from TripRepository
29 $tripRepository = new \Yatra\Repositories\TripRepository();
30 $price_stats = $tripRepository->getPriceRangeStats();
31
32 $min_price = (int) floor((float) ($options['min_price'] ?? ($price_stats->min_price ?? 100)));
33 $max_price = (int) ceil((float) ($options['max_price'] ?? ($price_stats->max_price ?? 5000)));
34 // Step 1 so the range slider can reach the true max exactly. A coarser
35 // step only lets the thumb stop on min + N*step, capping the slider
36 // short of the real maximum when (max - min) isn't a whole multiple of
37 // that step (e.g. min 9 / max 10000 / step 100 stops at 9909).
38 $step = $options['step'] ?? 1;
39
40 ob_start();
41 ?>
42 <div class="yatra-filter-section">
43 <div class="yatra-filter-title" data-toggle="price">
44 <div class="yatra-filter-title-content">
45 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
46 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1"/>
47 </svg>
48 <span>Price Range</span>
49 </div>
50 <div class="yatra-filter-actions">
51 <span class="yatra-clear-section" data-section="price">Clear</span>
52 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
53 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
54 </svg>
55 </div>
56 </div>
57 <div class="yatra-filter-content">
58 <div class="yatra-price-range">
59 <div class="yatra-price-inputs">
60 <div class="yatra-price-input-group">
61 <label class="yatra-price-input-label">Min Price</label>
62 <input type="number" name="price_min" placeholder="<?php echo $min_price; ?>" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" value="<?php echo !empty($active_filters['price_min']) ? esc_attr($active_filters['price_min']) : ''; ?>" id="priceMin">
63 </div>
64 <div class="yatra-price-separator"></div>
65 <div class="yatra-price-input-group">
66 <label class="yatra-price-input-label">Max Price</label>
67 <input type="number" name="price_max" placeholder="<?php echo $max_price; ?>" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" value="<?php echo !empty($active_filters['price_max']) ? esc_attr($active_filters['price_max']) : ''; ?>" id="priceMax">
68 </div>
69 </div>
70 <div class="yatra-price-slider">
71 <div class="yatra-price-slider-track" aria-hidden="true"></div>
72 <div class="yatra-price-slider-range" aria-hidden="true"></div>
73 <input type="range" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" step="<?php echo $step; ?>" value="<?php echo !empty($active_filters['price_min']) ? esc_attr($active_filters['price_min']) : $min_price; ?>" class="yatra-range-min" id="priceRangeMin" data-default="<?php echo esc_attr((string) $min_price); ?>">
74 <input type="range" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" step="<?php echo $step; ?>" value="<?php echo !empty($active_filters['price_max']) ? esc_attr($active_filters['price_max']) : $max_price; ?>" class="yatra-range-max" id="priceRangeMax" data-default="<?php echo esc_attr((string) $max_price); ?>">
75 </div>
76 <div class="yatra-price-display"><?php echo yatra_format_price($min_price); ?> - <?php echo yatra_format_price($max_price); ?></div>
77 </div>
78 </div>
79 </div>
80 <?php
81 return ob_get_clean();
82 }
83
84 /**
85 * Render difficulty level filter component
86 *
87 * @param array $active_filters Current active filters
88 * @param array $options Filter options
89 * @return string HTML output
90 */
91 public function renderDifficultyFilter(array $active_filters = [], array $options = []): string
92 {
93 $difficulty_service = new DifficultyLevelService();
94 $difficulty_levels = $difficulty_service->getPublished(['order_by' => 'sorting', 'order' => 'ASC']);
95
96 if (empty($difficulty_levels)) {
97 return '';
98 }
99
100 ob_start();
101 ?>
102 <div class="yatra-filter-section">
103 <div class="yatra-filter-title" data-toggle="difficulty">
104 <div class="yatra-filter-title-content">
105 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
106 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
107 </svg>
108 <span>Difficulty Level</span>
109 </div>
110 <div class="yatra-filter-actions">
111 <span class="yatra-clear-section" data-section="difficulty">Clear</span>
112 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
113 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
114 </svg>
115 </div>
116 </div>
117 <div class="yatra-filter-content">
118 <div class="yatra-checkbox-group">
119 <?php foreach ($difficulty_levels as $level) :
120 // Get trip count for this difficulty level
121 $tripRepository = new \Yatra\Repositories\TripRepository();
122 $trip_count = $tripRepository->countByDifficultyLevel($level->id);
123 ?>
124 <label class="yatra-checkbox-label">
125 <input type="checkbox" name="difficulty[]" value="<?php echo esc_attr($level->id); ?>" <?php echo in_array($level->id, $active_filters['difficulty'] ?? []) ? 'checked' : ''; ?>>
126 <span><?php echo esc_html($level->name); ?></span>
127 <span class="yatra-filter-count">(<?php echo (int)$trip_count; ?>)</span>
128 </label>
129 <?php endforeach; ?>
130 </div>
131 </div>
132 </div>
133 <?php
134 return ob_get_clean();
135 }
136
137 /**
138 * Render rating filter component
139 *
140 * @param array $active_filters Current active filters
141 * @param array $options Filter options
142 * @return string HTML output
143 */
144 public function renderRatingFilter(array $active_filters = [], array $options = []): string
145 {
146 ob_start();
147 ?>
148 <div class="yatra-filter-section">
149 <div class="yatra-filter-title" data-toggle="rating">
150 <div class="yatra-filter-title-content">
151 <svg class="yatra-filter-icon" width="18" height="18" fill="#fbbf24" viewBox="0 0 24 24">
152 <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
153 </svg>
154 <span>Rating</span>
155 </div>
156 <div class="yatra-filter-actions">
157 <span class="yatra-clear-section" data-section="rating">Clear</span>
158 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
159 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
160 </svg>
161 </div>
162 </div>
163 <div class="yatra-filter-content">
164 <div class="yatra-rating-filter">
165 <?php
166 global $wpdb;
167 $rating_options = [
168 ['stars' => 5, 'label' => 'And Up'],
169 ['stars' => 4, 'label' => 'And Up'],
170 ['stars' => 3, 'label' => 'And Up'],
171 ['stars' => 2, 'label' => 'And Up'],
172 ['stars' => 1, 'label' => 'And Up']
173 ];
174
175 // Check if reviews table exists and get trip counts
176 $tripRepository = new \Yatra\Repositories\TripRepository();
177 $reviews_table_exists = $tripRepository->reviewsTableExists();
178
179 foreach ($rating_options as $option) :
180 // Get trip count for this rating and above
181 $trip_count = 0;
182 if ($reviews_table_exists) {
183 $trip_count = $tripRepository->countByMinRating($option['stars']);
184 }
185 ?>
186 <label class="yatra-rating-option">
187 <input type="checkbox" name="rating[]" value="<?php echo esc_attr($option['stars']); ?>" <?php echo in_array($option['stars'], $active_filters['rating'] ?? []) ? 'checked' : ''; ?>>
188 <div class="yatra-stars-display">
189 <?php for ($i = 1; $i <= 5; $i++) : ?>
190 <svg class="yatra-star <?php echo $i <= $option['stars'] ? 'filled' : 'empty'; ?>" width="16" height="16" viewBox="0 0 24 24">
191 <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" fill="<?php echo $i <= $option['stars'] ? '#fbbf24' : '#e5e7eb'; ?>"/>
192 </svg>
193 <?php endfor; ?>
194 <span class="yatra-rating-label"><?php echo esc_html($option['label']); ?></span>
195 </div>
196 </label>
197 <?php endforeach; ?>
198 </div>
199 </div>
200 </div>
201 <?php
202 return ob_get_clean();
203 }
204
205 /**
206 * Render categories filter component
207 *
208 * @param array $active_filters Current active filters
209 * @param array $options Filter options
210 * @return string HTML output
211 */
212 public function renderCategoriesFilter(array $active_filters = [], array $options = []): string
213 {
214 $category_service = new TripCategoryService();
215 $categories = $category_service->getPublished(['order_by' => 'name', 'order' => 'ASC']);
216
217 if (empty($categories)) {
218 return '';
219 }
220
221 ob_start();
222 ?>
223 <div class="yatra-filter-section">
224 <div class="yatra-filter-title" data-toggle="categories">
225 <div class="yatra-filter-title-content">
226 <svg class="yatra-filter-icon" width="18" height="18" fill="currentColor" viewBox="0 0 20 20">
227 <path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z" clip-rule="evenodd" />
228 </svg>
229 <span>Categories</span>
230 </div>
231 <div class="yatra-filter-actions">
232 <span class="yatra-clear-section" data-section="categories">Clear</span>
233 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
234 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
235 </svg>
236 </div>
237 </div>
238 <div class="yatra-filter-content">
239 <div class="yatra-checkbox-group">
240 <?php foreach ($categories as $category) :
241 // Get trip count for this category
242 $tripRepository = new \Yatra\Repositories\TripRepository();
243 $trip_count = $tripRepository->countByCategory($category->id);
244
245 if ($trip_count > 0) :
246 ?>
247 <label class="yatra-checkbox-label">
248 <input type="checkbox" name="categories[]" value="<?php echo esc_attr($category->id); ?>" <?php echo in_array($category->id, $active_filters['categories'] ?? []) ? 'checked' : ''; ?>>
249 <span><?php echo esc_html($category->name); ?></span>
250 <span class="yatra-filter-count">(<?php echo (int)$trip_count; ?>)</span>
251 </label>
252 <?php endif; endforeach; ?>
253 </div>
254 </div>
255 </div>
256 <?php
257 return ob_get_clean();
258 }
259
260 /**
261 * Render destinations filter component
262 *
263 * @param array $active_filters Current active filters
264 * @param array $options Filter options
265 * @return string HTML output
266 */
267 public function renderDestinationsFilter(array $active_filters = [], array $options = []): string
268 {
269 $destination_service = new DestinationService();
270 $destinations = $destination_service->getPublished(['order_by' => 'name', 'order' => 'ASC', 'limit' => 15]);
271
272 if (empty($destinations)) {
273 return '';
274 }
275
276 ob_start();
277 ?>
278 <div class="yatra-filter-section">
279 <div class="yatra-filter-title" data-toggle="destinations">
280 <div class="yatra-filter-title-content">
281 <svg class="yatra-filter-icon" width="18" height="18" fill="currentColor" viewBox="0 0 20 20">
282 <path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd" />
283 </svg>
284 <span>Destinations</span>
285 </div>
286 <div class="yatra-filter-actions">
287 <span class="yatra-clear-section" data-section="destinations">Clear</span>
288 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
289 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
290 </svg>
291 </div>
292 </div>
293 <div class="yatra-filter-content">
294 <div class="yatra-checkbox-group">
295 <?php foreach ($destinations as $destination) :
296 // Get trip count for this destination
297 $tripRepository = new \Yatra\Repositories\TripRepository();
298 $trip_count = $tripRepository->countByDestination($destination->id);
299
300 if ($trip_count > 0) :
301 ?>
302 <label class="yatra-checkbox-label">
303 <input type="checkbox" name="destinations[]" value="<?php echo esc_attr($destination->id); ?>" <?php echo in_array($destination->id, $active_filters['destinations'] ?? []) ? 'checked' : ''; ?>>
304 <span><?php echo esc_html($destination->name); ?></span>
305 <span class="yatra-filter-count">(<?php echo (int)$trip_count; ?>)</span>
306 </label>
307 <?php endif; endforeach; ?>
308 </div>
309 </div>
310 </div>
311 <?php
312 return ob_get_clean();
313 }
314
315 /**
316 * Render activities filter component
317 *
318 * @param array $active_filters Current active filters
319 * @param array $options Filter options
320 * @return string HTML output
321 */
322 public function renderActivitiesFilter(array $active_filters = [], array $options = []): string
323 {
324 $activity_service = new ActivityService();
325 $activities = $activity_service->getPublished(['order_by' => 'name', 'order' => 'ASC', 'limit' => 15]);
326
327 if (empty($activities)) {
328 return '';
329 }
330
331 ob_start();
332 ?>
333 <div class="yatra-filter-section">
334 <div class="yatra-filter-title" data-toggle="activities">
335 <div class="yatra-filter-title-content">
336 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
337 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
338 </svg>
339 <span>Activities</span>
340 </div>
341 <div class="yatra-filter-actions">
342 <span class="yatra-clear-section" data-section="activities">Clear</span>
343 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
344 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
345 </svg>
346 </div>
347 </div>
348 <div class="yatra-filter-content">
349 <div class="yatra-checkbox-group">
350 <?php foreach ($activities as $activity) :
351 // Get trip count for this activity
352 $tripRepository = new \Yatra\Repositories\TripRepository();
353 $trip_count = $tripRepository->countByActivity($activity->id);
354
355 if ($trip_count > 0) :
356 ?>
357 <label class="yatra-checkbox-label">
358 <input type="checkbox" name="activities[]" value="<?php echo esc_attr($activity->id); ?>" <?php echo in_array($activity->id, $active_filters['activities'] ?? []) ? 'checked' : ''; ?>>
359 <span><?php echo esc_html($activity->name); ?></span>
360 <span class="yatra-filter-count">(<?php echo (int)$trip_count; ?>)</span>
361 </label>
362 <?php endif; endforeach; ?>
363 </div>
364 </div>
365 </div>
366 <?php
367 return ob_get_clean();
368 }
369
370 /**
371 * Render complete filter sidebar
372 *
373 * @param array $active_filters Current active filters
374 * @param array $options Filter options and configuration
375 * @return string HTML output
376 */
377 public function renderFilterSidebar(array $active_filters = [], array $options = []): string
378 {
379 $enabled_filters = $options['enabled_filters'] ?? [
380 'price_range', 'difficulty', 'rating', 'categories', 'destinations', 'activities'
381 ];
382
383 ob_start();
384 ?>
385 <aside class="yatra-filter-sidebar">
386 <div class="yatra-filter-header">
387 <h2>Filters</h2>
388 <span class="yatra-clear-filters">Clear all</span>
389 </div>
390
391 <?php
392 foreach ($enabled_filters as $filter_type) {
393 switch ($filter_type) {
394 case 'price_range':
395 echo $this->renderPriceRangeFilter($active_filters, $options);
396 break;
397 case 'difficulty':
398 echo $this->renderDifficultyFilter($active_filters, $options);
399 break;
400 case 'rating':
401 echo $this->renderRatingFilter($active_filters, $options);
402 break;
403 case 'categories':
404 echo $this->renderCategoriesFilter($active_filters, $options);
405 break;
406 case 'destinations':
407 echo $this->renderDestinationsFilter($active_filters, $options);
408 break;
409 case 'activities':
410 echo $this->renderActivitiesFilter($active_filters, $options);
411 break;
412 }
413 }
414 ?>
415 </aside>
416 <?php
417 return ob_get_clean();
418 }
419
420 /**
421 * Get repository (required by BaseService)
422 */
423 protected function getRepository()
424 {
425 // FilterService doesn't need a repository
426 return null;
427 }
428 }
429