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

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

386 lines 13.8 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\TripsTable;
8 use Yatra\Database\Tables\ClassificationsTable;
9 use Yatra\Database\Tables\TripClassificationsTable;
10 use Yatra\Utils\QueryCache;
11 use Yatra\Utils\Cache;
12
13 /**
14 * Trip Attribute Repository
15 * Handles database operations for trip-attribute relationships
16 */
17 class TripAttributeRepository extends BaseRepository
18 {
19 /**
20 * Get table name
21 */
22 public function getTableName(): string
23 {
24 return TripClassificationsTable::getTableName();
25 }
26
27 /**
28 * Get table name (protected for internal use)
29 */
30 protected function getTableNameInternal(): string
31 {
32 return TripClassificationsTable::getTableName();
33 }
34
35 /**
36 * Resolve field_type from the attribute definition (classifications.metadata).
37 */
38 private function resolveFieldTypeFromAttributeDefinition(int $attributeId): string
39 {
40 $attrRepo = new AttributeRepository();
41 $def = $attrRepo->find($attributeId);
42 if (!$def || empty($def->metadata)) {
43 return 'text';
44 }
45 $meta = json_decode((string) $def->metadata, true);
46 if (is_array($meta) && !empty($meta['field_type']) && is_string($meta['field_type'])) {
47 return $meta['field_type'];
48 }
49
50 return 'text';
51 }
52
53 /**
54 * @param array<mixed> $arr
55 */
56 private function isListArray(array $arr): bool
57 {
58 if (function_exists('array_is_list')) {
59 return array_is_list($arr);
60 }
61
62 $i = 0;
63 foreach ($arr as $k => $_) {
64 if ($k !== $i++) {
65 return false;
66 }
67 }
68
69 return true;
70 }
71
72 private function bustTripAttributeQueryCache(int $tripId): void
73 {
74 Cache::delete(Cache::KEY_TRIP_ATTRIBUTES . '_' . $tripId);
75 }
76
77 /**
78 * Save trip attributes
79 */
80 public function saveTripAttributes(int $tripId, array $attributes): bool
81 {
82 // Writes must not go through read-cache (Cache::remember).
83 global $wpdb;
84 $table_trip_classifications = $this->getTableNameInternal();
85
86 $table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$table_trip_classifications}'");
87 if (!$table_exists) {
88 return false;
89 }
90
91 $wpdb->query('START TRANSACTION');
92
93 try {
94 $wpdb->query($wpdb->prepare(
95 "DELETE FROM {$table_trip_classifications}
96 WHERE trip_id = %d
97 AND classification_type = 'attribute'",
98 $tripId
99 ));
100
101 if ($attributes === []) {
102 $wpdb->query('COMMIT');
103 $this->bustTripAttributeQueryCache($tripId);
104 do_action('yatra_trip_attributes_bulk_updated', $tripId, []);
105
106 return true;
107 }
108
109 foreach ($attributes as $attributeId => $value) {
110 $actualAttributeId = null;
111 $fieldType = null;
112 $actualValue = null;
113
114 if (is_numeric($attributeId) && is_array($value)) {
115 $actualAttributeId = (int) $attributeId;
116 $resolvedType = $this->resolveFieldTypeFromAttributeDefinition($actualAttributeId);
117
118 if (array_key_exists('value', $value)) {
119 $fieldType = isset($value['field_type']) && is_string($value['field_type']) && $value['field_type'] !== ''
120 ? $value['field_type']
121 : $resolvedType;
122 $actualValue = $value['value'];
123 } elseif ($this->isListArray($value)) {
124 $fieldType = $resolvedType;
125 $actualValue = $value;
126 } else {
127 $fieldType = isset($value['field_type']) && is_string($value['field_type']) && $value['field_type'] !== ''
128 ? $value['field_type']
129 : $resolvedType;
130 $actualValue = $value['value'] ?? $value;
131 }
132 } elseif (is_numeric($attributeId) && !is_array($value)) {
133 $actualAttributeId = (int) $attributeId;
134 $fieldType = $this->resolveFieldTypeFromAttributeDefinition($actualAttributeId);
135 $actualValue = $value;
136 } elseif (is_array($value)) {
137 $actualAttributeId = isset($value['id']) ? (int) $value['id'] :
138 (isset($value['attribute_id']) ? (int) $value['attribute_id'] : null);
139 if ($actualAttributeId === null || $actualAttributeId <= 0) {
140 continue;
141 }
142 $resolvedType = $this->resolveFieldTypeFromAttributeDefinition($actualAttributeId);
143
144 if (array_key_exists('value', $value)) {
145 $fieldType = isset($value['field_type']) && is_string($value['field_type']) && $value['field_type'] !== ''
146 ? $value['field_type']
147 : $resolvedType;
148 $actualValue = $value['value'];
149 } elseif ($this->isListArray($value)) {
150 $fieldType = $resolvedType;
151 $actualValue = $value;
152 } else {
153 $fieldType = isset($value['field_type']) && is_string($value['field_type']) && $value['field_type'] !== ''
154 ? $value['field_type']
155 : $resolvedType;
156 $actualValue = $value['value'] ?? $value;
157 }
158 } else {
159 continue;
160 }
161
162 if ($actualAttributeId === null || $actualAttributeId <= 0) {
163 continue;
164 }
165
166 if ($fieldType === 'text' || $fieldType === '') {
167 $fieldType = $this->resolveFieldTypeFromAttributeDefinition($actualAttributeId);
168 }
169
170 $metadata = [
171 'field_type' => $fieldType,
172 'value' => $actualValue,
173 ];
174
175 $result = $wpdb->insert(
176 $table_trip_classifications,
177 [
178 'trip_id' => $tripId,
179 'classification_id' => $actualAttributeId,
180 'classification_type' => 'attribute',
181 'relationship_type' => 'primary',
182 'metadata' => wp_json_encode($metadata),
183 'sort_order' => 0,
184 'is_featured' => 0,
185 'is_active' => 1,
186 'created_at' => current_time('mysql'),
187 'updated_at' => current_time('mysql'),
188 ],
189 ['%d', '%d', '%s', '%s', '%s', '%d', '%d', '%d', '%s', '%s']
190 );
191
192 if ($result === false) {
193 throw new \Exception('Failed to insert trip attribute relationship');
194 }
195 }
196
197 $wpdb->query('COMMIT');
198 $this->bustTripAttributeQueryCache($tripId);
199 do_action('yatra_trip_attributes_bulk_updated', $tripId, $attributes);
200
201 return true;
202 } catch (\Exception $e) {
203 $wpdb->query('ROLLBACK');
204
205 return false;
206 }
207 }
208
209 /**
210 * Get trip attributes with attribute details
211 */
212 public function getTripAttributes(int $tripId): array
213 {
214 global $wpdb;
215 $table_trip_classifications = $this->getTableNameInternal();
216 $table_classifications = ClassificationsTable::getTableName();
217
218 // Check if tables exist first
219 $trip_table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$table_trip_classifications}'");
220 $class_table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$table_classifications}'");
221
222 if (!$trip_table_exists || !$class_table_exists) {
223 if (defined('WP_DEBUG') && WP_DEBUG) {
224 }
225 return [];
226 }
227
228 // Get attributes from the trip_classifications table joined with classifications
229 $rows = $wpdb->get_results($wpdb->prepare(
230 "SELECT tc.id as relationship_id, tc.metadata as relationship_metadata,
231 tc.created_at, tc.updated_at,
232 c.id as attribute_id, c.name, c.slug, c.description, c.icon, c.metadata,
233 JSON_UNQUOTE(JSON_EXTRACT(tc.metadata, '$.field_type')) as field_type,
234 JSON_UNQUOTE(JSON_EXTRACT(tc.metadata, '$.value')) as value,
235 JSON_EXTRACT(c.metadata, '$.field_options') as field_options,
236 JSON_EXTRACT(c.metadata, '$.required') as required,
237 JSON_EXTRACT(c.metadata, '$.show_on_frontend') as show_on_frontend,
238 JSON_EXTRACT(c.metadata, '$.show_in_filters') as show_in_filters
239 FROM {$table_trip_classifications} tc
240 INNER JOIN {$table_classifications} c ON tc.classification_id = c.id
241 WHERE tc.trip_id = %d
242 AND tc.classification_type = 'attribute'
243 AND tc.is_active = 1
244 AND c.status = 'publish'
245 ORDER BY tc.sort_order ASC, c.name ASC",
246 $tripId
247 )) ?: [];
248
249 foreach ($rows as $row) {
250 if (!empty($row->relationship_metadata)) {
251 $rel = json_decode($row->relationship_metadata, true);
252 if (is_array($rel) && array_key_exists('value', $rel)) {
253 $row->value = $rel['value'];
254 }
255 }
256 if (!empty($row->metadata)) {
257 $def = json_decode($row->metadata, true);
258 if (is_array($def) && isset($def['field_options']) && is_array($def['field_options'])) {
259 $row->field_options = wp_json_encode($def['field_options']);
260 }
261 if (is_array($def) && !empty($def['field_type']) && is_string($def['field_type'])) {
262 $row->field_type = $def['field_type'];
263 }
264 }
265 }
266
267 return $rows;
268 }
269
270 /**
271 * Update trip attribute value
272 */
273 public function updateTripAttribute(int $tripId, int $attributeId, string $value): bool
274 {
275 global $wpdb;
276 $table_trip_classifications = $this->getTableNameInternal();
277
278 // Update the value in metadata JSON
279 return $wpdb->query($wpdb->prepare(
280 "UPDATE {$table_trip_classifications}
281 SET metadata = JSON_SET(
282 metadata, '$.value', %s,
283 metadata, '$.updated_at', %s
284 ),
285 updated_at = %s
286 WHERE trip_id = %d
287 AND classification_id = %d
288 AND classification_type = 'attribute'",
289 $value,
290 current_time('mysql'),
291 current_time('mysql'),
292 $tripId,
293 $attributeId
294 )) !== false;
295 }
296
297 /**
298 * Set trip attribute value
299 */
300 public function setTripAttribute(int $tripId, int $attributeId, $value): bool
301 {
302 global $wpdb;
303 $table_trip_classifications = $this->getTableNameInternal();
304
305 // Check if relationship already exists
306 $existing = $wpdb->get_row($wpdb->prepare(
307 "SELECT id FROM {$table_trip_classifications}
308 WHERE trip_id = %d AND classification_id = %d AND classification_type = 'attribute'",
309 $tripId, $attributeId
310 ));
311
312 // Store only essential data: field_type and value
313 $metadata = [
314 'field_type' => 'text', // Default field type
315 'value' => $value
316 ];
317
318 // Debug logging
319 if (defined('WP_DEBUG') && WP_DEBUG) {
320 }
321
322 if ($existing) {
323 // Update existing relationship
324 $result = $wpdb->update(
325 $table_trip_classifications,
326 ['metadata' => json_encode($metadata), 'updated_at' => current_time('mysql')],
327 ['trip_id' => $tripId, 'classification_id' => $attributeId, 'classification_type' => 'attribute']
328 );
329
330 if (defined('WP_DEBUG') && WP_DEBUG) {
331 }
332
333 return $result !== false;
334 } else {
335 // Insert new relationship
336 $result = $wpdb->insert(
337 $table_trip_classifications,
338 [
339 'trip_id' => $tripId,
340 'classification_id' => $attributeId,
341 'classification_type' => 'attribute',
342 'metadata' => json_encode($metadata),
343 'created_at' => current_time('mysql'),
344 'updated_at' => current_time('mysql')
345 ]
346 );
347
348 if (defined('WP_DEBUG') && WP_DEBUG) {
349 }
350
351 return $result !== false;
352 }
353 }
354
355 /**
356 * Delete trip attribute relationship
357 */
358 public function deleteTripAttribute(int $tripId, int $attributeId): bool
359 {
360 global $wpdb;
361 $table_trip_classifications = $this->getTableNameInternal();
362
363 return $wpdb->delete($table_trip_classifications, [
364 'trip_id' => $tripId,
365 'classification_id' => $attributeId,
366 'classification_type' => 'attribute'
367 ]) !== false;
368 }
369
370 /**
371 * Delete all trip attributes
372 */
373 public function deleteAllTripAttributes(int $tripId): bool
374 {
375 global $wpdb;
376 $table_trip_classifications = $this->getTableNameInternal();
377
378 return $wpdb->query($wpdb->prepare(
379 "DELETE FROM {$table_trip_classifications}
380 WHERE trip_id = %d
381 AND classification_type = 'attribute'",
382 $tripId
383 )) !== false;
384 }
385 }
386