PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.8
Yatra – Travel Booking & Tour Operator Software v3.0.8
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 / Repositories / TripDownloadRepository.php

TripDownloadRepository.php in Yatra – Travel Booking & Tour Operator Software 3.0.8, at app/Repositories/TripDownloadRepository.php

571 lines 19.7 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\Repositories;
6
7 use Yatra\Database\Tables\TripContentTable;
8
9 /**
10 * Trip Download Repository
11 *
12 * Handles CRUD operations for trip downloadable files.
13 * Downloads is a FREE feature in Yatra.
14 *
15 * @package Yatra\Repositories
16 * @since 3.0.0
17 */
18 class TripDownloadRepository
19 {
20 private function table(): string
21 {
22 return TripContentTable::getTableName();
23 }
24
25 /**
26 * Ensure the table exists, create if not
27 */
28 private function ensureTableExists(): bool
29 {
30 global $wpdb;
31 $table = $this->table();
32
33 if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'")) {
34 return true;
35 }
36
37 // Create the table if it doesn't exist
38 if (class_exists('\\Yatra\\Services\\InstallerService')) {
39 \Yatra\Services\InstallerService::createDatabaseTables();
40 }
41
42 return (bool) $wpdb->get_var("SHOW TABLES LIKE '{$table}'");
43 }
44
45 /**
46 * Get all downloads for a trip
47 */
48 public function getByTripId(int $tripId): array
49 {
50 global $wpdb;
51 $table = $this->table();
52
53 if (!$this->ensureTableExists()) {
54 return [];
55 }
56
57 $sql = $wpdb->prepare(
58 "SELECT * FROM {$table} WHERE trip_id = %d AND content_type = 'download' ORDER BY sort_order ASC, id ASC",
59 $tripId
60 );
61
62
63 $rows = $wpdb->get_results($sql) ?: [];
64
65 // Normalize metadata back into expected fields - match TripRepository structure
66 $normalizedRows = [];
67 foreach ($rows as $row) {
68 $metadata = [];
69 if (!empty($row->metadata)) {
70 $decoded = json_decode($row->metadata, true);
71 if (is_array($decoded)) {
72 $metadata = $decoded;
73 }
74 }
75
76 $attachmentId = $metadata['attachment_id'] ?? null;
77 $protectedPath = $metadata['protected_path'] ?? null;
78 $visibilityMeta = $metadata['visibility'] ?? null;
79
80 // Use visibility from metadata as primary source of truth
81 // Fall back to access_level mapping only if metadata is missing
82 $visibility = $visibilityMeta ?? 'booked_only';
83 if ($visibilityMeta === null) {
84 // Only use access_level if visibility metadata is not set
85 if ($row->access_level === 'public') {
86 $visibility = 'public';
87 } elseif ($row->access_level === 'registered') {
88 $visibility = 'logged_in';
89 } elseif ($row->access_level === 'customer') {
90 $visibility = 'booked_only';
91 }
92 }
93
94 // Create normalized object matching TripRepository structure
95 $normalizedRows[] = (object) [
96 'id' => isset($row->id) ? (int) $row->id : 0,
97 'title' => $row->title ?? '',
98 'description' => $row->description ?? '',
99 'attachment_id' => $attachmentId ? (int) $attachmentId : null,
100 'protected_path' => $protectedPath,
101 'content_url' => $row->content_url ?? '',
102 'file_path' => $row->file_path ?? null,
103 'file_size' => isset($row->file_size) ? (int) $row->file_size : null,
104 'file_type' => $row->file_type ?? null,
105 'thumbnail_url' => $row->thumbnail_url ?? null,
106 'visibility' => $visibility,
107 'is_downloadable' => isset($row->is_downloadable) ? (bool) $row->is_downloadable : true,
108 'sort_order' => isset($row->sort_order) ? (int) $row->sort_order : 0,
109 ];
110 }
111
112 return $normalizedRows;
113 }
114
115 /**
116 * Get a download by ID
117 */
118 public function getById(int $id): ?object
119 {
120 global $wpdb;
121 $table = $this->table();
122
123 if (!$this->ensureTableExists()) {
124 return null;
125 }
126
127 $result = $wpdb->get_row(
128 $wpdb->prepare(
129 "SELECT * FROM {$table} WHERE id = %d AND content_type = 'download' LIMIT 1",
130 $id
131 )
132 );
133
134 if (!$result) {
135 return null;
136 }
137
138 // Parse metadata to extract visibility and attachment_id
139 $metadata = null;
140 if (!empty($result->metadata)) {
141 $metadata = json_decode($result->metadata, true);
142 }
143
144 // Extract visibility from metadata
145 if ($metadata && isset($metadata['visibility'])) {
146 $result->visibility = $metadata['visibility'];
147 } elseif (isset($result->access_level)) {
148 // Fallback to access_level for backward compatibility
149 $result->visibility = $result->access_level;
150 } else {
151 $result->visibility = 'booked_only'; // Default
152 }
153
154 // Extract attachment_id from metadata
155 if ($metadata && isset($metadata['attachment_id'])) {
156 $result->attachment_id = $metadata['attachment_id'];
157 }
158
159 return $result;
160 }
161
162 /**
163 * Update the protected path for a download
164 */
165 public function updateProtectedPath(int $id, string $protectedPath): void
166 {
167 global $wpdb;
168 $table = $this->table();
169
170 if (!$this->ensureTableExists()) {
171 return;
172 }
173
174 $wpdb->update(
175 $table,
176 ['protected_path' => sanitize_text_field($protectedPath)],
177 ['id' => $id, 'content_type' => 'download'],
178 ['%s'],
179 ['%d', '%s']
180 );
181 }
182
183 /**
184 * Replace all downloads for a trip
185 */
186 public function replaceForTrip(int $tripId, array $items): void
187 {
188 global $wpdb;
189 $table = $this->table();
190
191 if (!$this->ensureTableExists()) {
192 return;
193 }
194
195 // Delete existing downloads for this trip
196 $wpdb->delete($table, ['trip_id' => $tripId, 'content_type' => 'download'], ['%d', '%s']);
197
198 $order = 0;
199 foreach ($items as $item) {
200 if (!is_array($item)) {
201 continue;
202 }
203
204 $title = sanitize_text_field($item['title'] ?? '');
205 if ($title === '') {
206 continue;
207 }
208
209 // Normalize visibility
210 $visibility = sanitize_key($item['visibility'] ?? 'booked_only');
211 if ($visibility === 'paid_only') {
212 $visibility = 'booked_only';
213 }
214 if (!in_array($visibility, ['public', 'logged_in', 'booked_only'], true)) {
215 $visibility = 'booked_only';
216 }
217 $accessLevel = 'customer';
218 $isPublic = 0;
219 $requiresLogin = 1;
220 if ($visibility === 'public') {
221 $accessLevel = 'public';
222 $isPublic = 1;
223 $requiresLogin = 0;
224 } elseif ($visibility === 'logged_in') {
225 $accessLevel = 'registered';
226 $isPublic = 0;
227 $requiresLogin = 1;
228 }
229
230 $attachmentId = isset($item['attachment_id']) ? (int) $item['attachment_id'] : null;
231 $contentUrl = null;
232 $filePath = isset($item['file_path']) ? sanitize_text_field($item['file_path']) : null;
233 $fileType = isset($item['file_type']) ? sanitize_text_field($item['file_type']) : null;
234 $fileSize = isset($item['file_size']) ? (int) $item['file_size'] : null;
235 $thumbnailUrl = isset($item['thumbnail_url']) ? esc_url_raw($item['thumbnail_url']) : null;
236
237 if ($attachmentId) {
238 $contentUrl = wp_get_attachment_url($attachmentId) ?: null;
239 if (empty($filePath)) {
240 $filePath = get_attached_file($attachmentId) ?: null;
241 }
242 if (empty($fileType)) {
243 $fileType = wp_check_filetype(get_attached_file($attachmentId) ?: '')['type'] ?? null;
244 }
245 if (empty($fileSize)) {
246 $fileSize = (int) filesize(get_attached_file($attachmentId) ?: '') ?: null;
247 }
248 if (empty($thumbnailUrl)) {
249 $thumb = wp_get_attachment_image_src($attachmentId, 'thumbnail');
250 $thumbnailUrl = $thumb && isset($thumb[0]) ? $thumb[0] : null;
251 }
252 } elseif (!empty($item['content_url'])) {
253 $contentUrl = esc_url_raw($item['content_url']);
254 if (empty($fileType)) {
255 $fileType = wp_check_filetype($contentUrl)['type'] ?? null;
256 }
257 }
258
259 $metadata = [
260 'attachment_id' => $attachmentId,
261 'protected_path' => isset($item['protected_path']) ? sanitize_text_field($item['protected_path']) : null,
262 'visibility' => $visibility,
263 ];
264
265 $result = $wpdb->insert(
266 $table,
267 [
268 'trip_id' => $tripId,
269 'content_type' => 'download',
270 'title' => $title,
271 'description' => isset($item['description']) ? wp_kses_post($item['description']) : null,
272 'content_url' => $contentUrl,
273 'metadata' => wp_json_encode($metadata),
274 'file_path' => $filePath,
275 'file_size' => $fileSize,
276 'file_type' => $fileType,
277 'thumbnail_url' => $thumbnailUrl,
278 'display_options' => isset($item['display_options']) ? wp_json_encode($item['display_options']) : null,
279 'access_level' => $accessLevel,
280 'is_downloadable' => isset($item['enabled']) ? (int) (bool) $item['enabled'] : 1,
281 'is_public' => $isPublic,
282 'requires_login' => $requiresLogin,
283 'sort_order' => isset($item['sort_order']) ? (int) $item['sort_order'] : $order,
284 'created_by' => get_current_user_id() ?: null,
285 'updated_by' => get_current_user_id() ?: null,
286 ],
287 [
288 '%d', // trip_id
289 '%s', // content_type
290 '%s', // title
291 '%s', // description
292 '%s', // content_url
293 '%s', // metadata
294 '%s', // file_path
295 '%d', // file_size
296 '%s', // file_type
297 '%s', // thumbnail_url
298 '%s', // display_options
299 '%s', // access_level
300 '%d', // is_downloadable
301 '%d', // is_public
302 '%d', // requires_login
303 '%d', // sort_order
304 '%d', // created_by
305 '%d', // updated_by
306 ]
307 );
308
309
310 $order++;
311 }
312 }
313
314 /**
315 * Create a single download
316 */
317 public function create(array $data): ?int
318 {
319 global $wpdb;
320 $table = $this->table();
321
322 if (!$this->ensureTableExists()) {
323 return null;
324 }
325
326 $title = sanitize_text_field($data['title'] ?? '');
327 if ($title === '') {
328 return null;
329 }
330
331 $visibility = sanitize_key($data['visibility'] ?? 'booked_only');
332 if ($visibility === 'paid_only') {
333 $visibility = 'booked_only';
334 }
335 if (!in_array($visibility, ['public', 'logged_in', 'booked_only'], true)) {
336 $visibility = 'booked_only';
337 }
338
339 $accessLevel = 'customer';
340 $isPublic = 0;
341 $requiresLogin = 1;
342 if ($visibility === 'public') {
343 $accessLevel = 'public';
344 $isPublic = 1;
345 $requiresLogin = 0;
346 } elseif ($visibility === 'logged_in') {
347 $accessLevel = 'registered';
348 $isPublic = 0;
349 $requiresLogin = 1;
350 }
351
352 $attachmentId = isset($data['attachment_id']) ? (int) $data['attachment_id'] : null;
353 $contentUrl = $attachmentId ? (wp_get_attachment_url($attachmentId) ?: null) : (isset($data['content_url']) ? esc_url_raw($data['content_url']) : null);
354 $filePath = isset($data['file_path']) ? sanitize_text_field($data['file_path']) : null;
355 $fileType = isset($data['file_type']) ? sanitize_text_field($data['file_type']) : null;
356 $fileSize = isset($data['file_size']) ? (int) $data['file_size'] : null;
357 $thumbnailUrl = isset($data['thumbnail_url']) ? esc_url_raw($data['thumbnail_url']) : null;
358
359 if ($attachmentId) {
360 if (empty($filePath)) {
361 $filePath = get_attached_file($attachmentId) ?: null;
362 }
363 if (empty($fileType)) {
364 $fileType = wp_check_filetype(get_attached_file($attachmentId) ?: '')['type'] ?? null;
365 }
366 if (empty($fileSize)) {
367 $fileSize = (int) filesize(get_attached_file($attachmentId) ?: '') ?: null;
368 }
369 if (empty($thumbnailUrl)) {
370 $thumb = wp_get_attachment_image_src($attachmentId, 'thumbnail');
371 $thumbnailUrl = $thumb && isset($thumb[0]) ? $thumb[0] : null;
372 }
373 } elseif (!empty($data['content_url']) && empty($fileType)) {
374 $fileType = wp_check_filetype($data['content_url'])['type'] ?? null;
375 }
376
377 $metadata = [
378 'attachment_id' => $attachmentId,
379 'protected_path' => isset($data['protected_path']) ? sanitize_text_field($data['protected_path']) : null,
380 'visibility' => $visibility,
381 ];
382
383 $result = $wpdb->insert(
384 $table,
385 [
386 'trip_id' => (int) ($data['trip_id'] ?? 0),
387 'content_type' => 'download',
388 'title' => $title,
389 'description' => isset($data['description']) ? wp_kses_post($data['description']) : null,
390 'content_url' => $contentUrl,
391 'metadata' => wp_json_encode($metadata),
392 'file_path' => $filePath,
393 'file_size' => $fileSize,
394 'file_type' => $fileType,
395 'thumbnail_url' => $thumbnailUrl,
396 'display_options' => isset($data['display_options']) ? wp_json_encode($data['display_options']) : null,
397 'access_level' => $accessLevel,
398 'is_downloadable' => 1,
399 'is_public' => $isPublic,
400 'requires_login' => $requiresLogin,
401 'sort_order' => isset($data['sort_order']) ? (int) $data['sort_order'] : 0,
402 'created_by' => get_current_user_id() ?: null,
403 'updated_by' => get_current_user_id() ?: null,
404 ],
405 ['%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%d']
406 );
407
408 return $result ? (int) $wpdb->insert_id : null;
409 }
410
411 /**
412 * Update a download
413 */
414 public function update(int $id, array $data): bool
415 {
416 global $wpdb;
417 $table = $this->table();
418
419 if (!$this->ensureTableExists()) {
420 return false;
421 }
422
423 $updateData = [];
424 $formats = [];
425
426 if (isset($data['title'])) {
427 $updateData['title'] = sanitize_text_field($data['title']);
428 $formats[] = '%s';
429 }
430
431 if (isset($data['description'])) {
432 $updateData['description'] = wp_kses_post($data['description']);
433 $formats[] = '%s';
434 }
435
436 $metadata = [];
437 if (!empty($existing = $this->getById($id))) {
438 if (!empty($existing->metadata)) {
439 $decoded = json_decode($existing->metadata, true);
440 if (is_array($decoded)) {
441 $metadata = $decoded;
442 }
443 }
444 }
445
446 if (isset($data['attachment_id'])) {
447 $attachmentId = (int) $data['attachment_id'];
448 $updateData['content_url'] = $attachmentId ? (wp_get_attachment_url($attachmentId) ?: null) : null;
449 $formats[] = '%s';
450 $metadata['attachment_id'] = $attachmentId;
451 }
452 if (isset($data['content_url'])) {
453 $updateData['content_url'] = esc_url_raw($data['content_url']);
454 $formats[] = '%s';
455 }
456
457 if (isset($data['protected_path'])) {
458 $metadata['protected_path'] = sanitize_text_field($data['protected_path']);
459 }
460
461 if (isset($data['visibility'])) {
462 $visibility = sanitize_key($data['visibility']);
463 if ($visibility === 'paid_only') {
464 $visibility = 'booked_only';
465 }
466 if (!in_array($visibility, ['public', 'logged_in', 'booked_only'], true)) {
467 $visibility = 'booked_only';
468 }
469 $accessLevel = 'customer';
470 $isPublic = 0;
471 $requiresLogin = 1;
472 if ($visibility === 'public') {
473 $accessLevel = 'public';
474 $isPublic = 1;
475 $requiresLogin = 0;
476 } elseif ($visibility === 'logged_in') {
477 $accessLevel = 'registered';
478 $isPublic = 0;
479 $requiresLogin = 1;
480 }
481 $updateData['access_level'] = $accessLevel;
482 $formats[] = '%s';
483 $updateData['is_public'] = $isPublic;
484 $formats[] = '%d';
485 $updateData['requires_login'] = $requiresLogin;
486 $formats[] = '%d';
487 $metadata['visibility'] = $visibility;
488 }
489
490 if (!empty($metadata)) {
491 $updateData['metadata'] = wp_json_encode($metadata);
492 $formats[] = '%s';
493 }
494
495 if (isset($data['file_path'])) {
496 $updateData['file_path'] = sanitize_text_field($data['file_path']);
497 $formats[] = '%s';
498 }
499 if (isset($data['file_size'])) {
500 $updateData['file_size'] = (int) $data['file_size'];
501 $formats[] = '%d';
502 }
503 if (isset($data['file_type'])) {
504 $updateData['file_type'] = sanitize_text_field($data['file_type']);
505 $formats[] = '%s';
506 }
507 if (isset($data['thumbnail_url'])) {
508 $updateData['thumbnail_url'] = esc_url_raw($data['thumbnail_url']);
509 $formats[] = '%s';
510 }
511 if (isset($data['display_options'])) {
512 $updateData['display_options'] = wp_json_encode($data['display_options']);
513 $formats[] = '%s';
514 }
515
516 if (isset($data['enabled'])) {
517 $updateData['is_downloadable'] = (int) (bool) $data['enabled']; // Map enabled to is_downloadable
518 $formats[] = '%d';
519 }
520
521 if (isset($data['sort_order'])) {
522 $updateData['sort_order'] = (int) $data['sort_order'];
523 $formats[] = '%d';
524 }
525
526 if (!empty($updateData)) {
527 $result = $wpdb->update(
528 $table,
529 $updateData,
530 ['id' => $id, 'content_type' => 'download'],
531 $formats,
532 ['%d', '%s']
533 );
534 }
535
536 return !empty($updateData) ? $result !== false : true;
537 }
538
539 /**
540 * Delete a download
541 */
542 public function delete(int $id): bool
543 {
544 global $wpdb;
545 $table = $this->table();
546
547 if (!$this->ensureTableExists()) {
548 return false;
549 }
550
551 $result = $wpdb->delete($table, ['id' => $id, 'content_type' => 'download'], ['%d', '%s']);
552 return $result !== false;
553 }
554
555 /**
556 * Delete all downloads for a trip
557 */
558 public function deleteByTripId(int $tripId): bool
559 {
560 global $wpdb;
561 $table = $this->table();
562
563 if (!$this->ensureTableExists()) {
564 return false;
565 }
566
567 $result = $wpdb->delete($table, ['trip_id' => $tripId, 'content_type' => 'download'], ['%d', '%s']);
568 return $result !== false;
569 }
570 }
571