PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.6
Yatra – Travel Booking & Tour Operator Software v3.0.6
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 / TripCategoryController.php

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

311 lines 10.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\Services\CategoryService;
11 use Yatra\Database\Tables\TripsTable;
12 use Yatra\Database\Tables\TripClassificationsTable;
13
14 /**
15 * Trip Category REST API Controller
16 *
17 * Endpoints:
18 * - GET /trip-categories - List categories
19 * - POST /trip-categories - Create category
20 * - GET /trip-categories/{id} - Get single category
21 * - PUT /trip-categories/{id} - Update category
22 * - DELETE /trip-categories/{id} - Delete category
23 * - GET /trip-categories/{id}/subcategories - Get subcategories
24 */
25 class TripCategoryController extends BaseController
26 {
27 protected string $rest_base = 'trip-categories';
28
29 private CategoryService $service;
30
31 public function __construct()
32 {
33 $this->service = new CategoryService();
34 }
35
36 public function register_routes(): void
37 {
38 // Register CRUD routes with additional args
39 $this->registerCrudRoutes(array_merge(
40 $this->getStatusArg(),
41 [
42 'hierarchical' => [
43 'default' => false,
44 'sanitize_callback' => 'rest_sanitize_boolean',
45 ],
46 'parent_id' => [
47 'default' => null,
48 'sanitize_callback' => 'absint',
49 ],
50 ]
51 ));
52
53 // Additional route: Get subcategories
54 $this->registerRoute('/' . $this->rest_base . '/(?P<id>[\d]+)/subcategories', [
55 [
56 'methods' => \WP_REST_Server::READABLE,
57 'callback' => [$this, 'get_subcategories'],
58 'permission_callback' => [$this, 'check_permission'],
59 ],
60 ]);
61 }
62
63 public function check_permission(?WP_REST_Request $request = null): bool
64 {
65 if ($request === null) {
66 return true;
67 }
68
69 if (!is_user_logged_in()) {
70 return false;
71 }
72
73 if (current_user_can('manage_options')) {
74 return true;
75 }
76
77 switch ($request->get_method()) {
78 case 'GET':
79 return current_user_can('yatra_view_trips');
80 case 'POST':
81 case 'PUT':
82 case 'PATCH':
83 case 'DELETE':
84 return current_user_can('yatra_edit_trips');
85 default:
86 // Unknown HTTP method — deny explicitly. The earlier
87 // fallback to `manage_options` was a regression that
88 // silently broadened admin-only access for any verb not
89 // in the explicit switch.
90 return false;
91 }
92 }
93
94 public function get_items(WP_REST_Request $request)
95 {
96
97 try {
98 $params = $this->getPaginationParams($request);
99
100 $args = [
101 'limit' => $params['per_page'],
102 'offset' => ($params['page'] - 1) * $params['per_page'],
103 'order_by' => $params['orderby'],
104 'order' => $params['order'],
105 ];
106
107 if (!empty($params['search'])) {
108 $args['search'] = $params['search'];
109 }
110
111 $status = $request->get_param('status');
112 if ($status && $status !== 'all') {
113 $args['status'] = sanitize_text_field($status);
114 }
115
116 // Handle hierarchical and parent_id with proper implementation
117 $hierarchical = $request->get_param('hierarchical');
118 if ($hierarchical) {
119 // Use proper hierarchical implementation
120 $items = $this->service->getHierarchical($args);
121 } else {
122 $parent_id = $request->get_param('parent_id');
123 if ($parent_id !== null) {
124 // Get subcategories for specific parent
125 $items = $this->service->getSubcategories((int) $parent_id, $args);
126 } else {
127 // Get all categories
128 $items = $this->service->getAll($args);
129 }
130 }
131
132 $total = $this->service->count($args);
133
134 // Attach trip counts for each category using service methods
135 if (!empty($items)) {
136 $attachCounts = function (&$categories) use (&$attachCounts) {
137 if (empty($categories) || !is_array($categories)) {
138 return;
139 }
140
141 foreach ($categories as &$cat) {
142 $categoryId = isset($cat->id) ? (int) $cat->id : 0;
143 if ($categoryId > 0) {
144 $tripCount = $this->service->getTripCount($categoryId);
145 $cat->trip_count = $tripCount;
146 }
147
148 // Recursively attach counts to subcategories
149 if (isset($cat->subcategories) && is_array($cat->subcategories)) {
150 $attachCounts($cat->subcategories);
151 }
152 }
153 };
154
155 $attachCounts($items);
156 }
157
158 // Prepare all items including nested subcategories
159 $prepareAllItems = function (&$items) use (&$prepareAllItems) {
160 if (empty($items) || !is_array($items)) {
161 return;
162 }
163
164 foreach ($items as &$item) {
165 $item = (object) $this->prepareItem($item);
166
167 // Recursively prepare subcategories
168 if (isset($item->subcategories) && is_array($item->subcategories)) {
169 $prepareAllItems($item->subcategories);
170 }
171 }
172 };
173
174 $prepareAllItems($items);
175
176 return $this->paginated_response($items, $total, $params['page'], $params['per_page']);
177 } catch (\Exception $e) {
178 return $this->error_response($e->getMessage(), 500);
179 }
180 }
181
182 public function get_item(WP_REST_Request $request)
183 {
184 try {
185 $item = $this->service->getById($this->getId($request));
186
187 if (!$item) {
188 return $this->not_found(__('Category not found', 'yatra'));
189 }
190
191 // Attach trip count for single category using service methods
192 $categoryId = isset($item->id) ? (int) $item->id : 0;
193 if ($categoryId > 0) {
194 $tripCount = $this->service->getTripCount($categoryId);
195 $item->trip_count = $tripCount;
196 }
197
198 return $this->success_response($this->prepareItem($item));
199 } catch (\Exception $e) {
200 return $this->error_response($e->getMessage(), 500);
201 }
202 }
203
204 public function get_subcategories(WP_REST_Request $request)
205 {
206 try {
207 $subcategories = $this->service->getSubcategories($this->getId($request));
208
209 $prepared = array_map([$this, 'prepareItem'], $subcategories);
210
211 return $this->success_response($prepared);
212 } catch (\Exception $e) {
213 return $this->error_response($e->getMessage(), 500);
214 }
215 }
216
217 public function create_item(WP_REST_Request $request)
218 {
219 try {
220 $id = $this->service->create($this->getBody($request));
221
222 return $this->success_response([
223 'id' => $id,
224 'message' => __('Category created successfully', 'yatra'),
225 ], 201);
226 } catch (\InvalidArgumentException $e) {
227 return $this->validation_error($e->getMessage());
228 } catch (\Exception $e) {
229 return $this->error_response($e->getMessage(), 500);
230 }
231 }
232
233 public function update_item(WP_REST_Request $request)
234 {
235 try {
236 $result = $this->service->update($this->getId($request), $this->getBody($request));
237 if (!$result) {
238 return $this->error_response(__('Failed to update category', 'yatra'), 500);
239 }
240
241 return $this->success_response([
242 'message' => __('Category updated successfully', 'yatra'),
243 ]);
244 } catch (\InvalidArgumentException $e) {
245 return $this->validation_error($e->getMessage());
246 } catch (\Exception $e) {
247 return $this->error_response($e->getMessage(), 500);
248 }
249 }
250
251 public function delete_item(WP_REST_Request $request)
252 {
253 try {
254 $result = $this->service->delete($this->getId($request));
255
256 if (!$result) {
257 return $this->error_response(__('Failed to delete category', 'yatra'), 500);
258 }
259
260 return $this->success_response([
261 'message' => __('Category deleted successfully', 'yatra'),
262 ]);
263 } catch (\InvalidArgumentException $e) {
264 return $this->validation_error($e->getMessage());
265 } catch (\Exception $e) {
266 return $this->error_response($e->getMessage(), 500);
267 }
268 }
269
270 private function prepareItem($item): array
271 {
272
273 $prepared = (array) $item;
274
275 if (isset($prepared['icon']) && is_string($prepared['icon'])) {
276 $prepared['icon'] = maybe_unserialize($prepared['icon']);
277 }
278 if (isset($prepared['icon'])) {
279 $prepared['icon'] = $this->convert_icon_attachment_id_to_url($prepared['icon']);
280 }
281
282 // Handle metadata
283 if (isset($prepared['metadata']) && is_string($prepared['metadata'])) {
284 $prepared['metadata'] = maybe_unserialize($prepared['metadata']);
285 }
286
287
288 // Add parent name
289 if (!empty($prepared['parent_id'])) {
290 $parent = $this->service->getById((int) $prepared['parent_id']);
291 $prepared['parent_name'] = $parent ? $parent->name : null;
292 }
293
294 if (!empty($prepared['created_by'])) {
295 $user = get_userdata((int) $prepared['created_by']);
296 $prepared['created_by_name'] = $user ? esc_html($user->display_name) : null;
297 }
298
299 if (!empty($prepared['updated_by'])) {
300 $user = get_userdata((int) $prepared['updated_by']);
301 $prepared['updated_by_name'] = $user ? esc_html($user->display_name) : null;
302 }
303
304 if (array_key_exists('is_featured', $prepared)) {
305 $prepared['is_featured'] = !empty($prepared['is_featured']) ? 1 : 0;
306 }
307
308 return $prepared;
309 }
310 }
311