PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
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 / ItemController.php

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

289 lines 9.3 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\ItemService;
11 use Yatra\Repositories\ItemTypeRepository;
12 use Yatra\Repositories\ItemRepository;
13
14 /**
15 * Item REST API Controller
16 *
17 * Endpoints:
18 * - GET /items - List items
19 * - POST /items - Create item
20 * - GET /items/{id} - Get single item
21 * - PUT /items/{id} - Update item
22 * - DELETE /items/{id} - Delete item
23 */
24 class ItemController extends BaseController
25 {
26 protected string $rest_base = 'items';
27
28 private ItemService $service;
29 private ItemTypeRepository $itemTypeRepository;
30 private ItemRepository $repository;
31
32 public function __construct()
33 {
34 $this->service = new ItemService();
35 $this->itemTypeRepository = new ItemTypeRepository();
36 $this->repository = new ItemRepository();
37 }
38
39 public function register_routes(): void
40 {
41 $this->registerCrudRoutes(array_merge(
42 $this->getStatusArg(),
43 [
44 'type_id' => [
45 'default' => 'all',
46 'sanitize_callback' => 'absint',
47 ],
48 ]
49 ));
50
51 // Status statistics for admin views (All / Published / Draft / Trash)
52 register_rest_route($this->namespace, '/' . $this->rest_base . '/stats', [
53 [
54 'methods' => \WP_REST_Server::READABLE,
55 'callback' => [$this, 'getStats'],
56 'permission_callback' => [$this, 'check_permission'],
57 ],
58 ]);
59 }
60
61 /**
62 * GET /items/stats
63 * Return stable status counts for admin list views.
64 */
65 public function getStats(WP_REST_Request $request)
66 {
67 try {
68 $stats = $this->service->getStatusCounts();
69 return $this->success_response($stats);
70 } catch (\Exception $e) {
71 return $this->error_response($e->getMessage(), 500);
72 }
73 }
74
75 public function check_permission(?WP_REST_Request $request = null): bool
76 {
77 if ($request === null) {
78 return true;
79 }
80
81 if (!is_user_logged_in()) {
82 return false;
83 }
84
85 if (current_user_can('manage_options')) {
86 return true;
87 }
88
89 switch ($request->get_method()) {
90 case 'GET':
91 return current_user_can('yatra_view_trips');
92 case 'POST':
93 case 'PUT':
94 case 'PATCH':
95 case 'DELETE':
96 return current_user_can('yatra_edit_trips');
97 default:
98 // Unknown HTTP method — deny explicitly. The earlier
99 // fallback to `manage_options` was a regression that
100 // silently broadened admin-only access for any verb not
101 // in the explicit switch.
102 return false;
103 }
104 }
105
106 public function get_items(WP_REST_Request $request)
107 {
108 try {
109 $params = $this->getPaginationParams($request);
110
111 $args = [
112 'limit' => $params['per_page'],
113 'offset' => ($params['page'] - 1) * $params['per_page'],
114 'order_by' => $params['orderby'],
115 'order' => $params['order'],
116 ];
117
118 if (!empty($params['search'])) {
119 $args['search'] = $params['search'];
120 }
121
122 $type_id = $request->get_param('type_id');
123 if ($type_id && $type_id !== 'all') {
124 $args['type_id'] = absint($type_id);
125 }
126
127 $status = $request->get_param('status');
128 if ($status && $status !== 'all') {
129 $args['status'] = sanitize_text_field($status);
130 }
131
132 $items = $this->service->getAll($args);
133 $total = $this->service->count($args);
134
135 $prepared = array_map([$this, 'prepareItem'], $items);
136
137 // Get available item types for filter dropdown
138 $all_types = $this->itemTypeRepository->all(['where' => ['status' => 'publish']]);
139 $available_types = array_map(function ($type) {
140 return [
141 'id' => (int) $type->id,
142 'name' => esc_html($type->name),
143 ];
144 }, $all_types);
145
146 return new \WP_REST_Response([
147 'data' => $prepared,
148 'total' => $total,
149 'page' => $params['page'],
150 'per_page' => $params['per_page'],
151 'total_pages' => (int) ceil($total / $params['per_page']),
152 'meta' => [
153 'available_types' => array_values($available_types),
154 ],
155 ], 200);
156 } catch (\Exception $e) {
157 return $this->error_response($e->getMessage(), 500);
158 }
159 }
160
161 public function get_item(WP_REST_Request $request)
162 {
163 try {
164 $item = $this->service->getById($this->getId($request));
165
166 if (!$item) {
167 return $this->not_found(__('Item not found', 'yatra'));
168 }
169
170 return $this->success_response($this->prepareItem($item));
171 } catch (\Exception $e) {
172 return $this->error_response($e->getMessage(), 500);
173 }
174 }
175
176 public function create_item(WP_REST_Request $request)
177 {
178 try {
179 $id = $this->service->create($this->getBody($request));
180
181 // Get the created item to return full data
182 $item = $this->service->getById($id);
183
184 return $this->success_response([
185 'id' => $id,
186 'message' => __('Item created successfully', 'yatra'),
187 'data' => $item,
188 ], 201);
189 } catch (\InvalidArgumentException $e) {
190 return $this->validation_error($e->getMessage());
191 } catch (\Exception $e) {
192 return $this->error_response($e->getMessage(), 500);
193 }
194 }
195
196 public function update_item(WP_REST_Request $request)
197 {
198 try {
199 $result = $this->service->update($this->getId($request), $this->getBody($request));
200
201 if (!$result) {
202 return $this->error_response(__('Failed to update item', 'yatra'), 500);
203 }
204
205 return $this->success_response([
206 'message' => __('Item updated successfully', 'yatra'),
207 ]);
208 } catch (\InvalidArgumentException $e) {
209 return $this->validation_error($e->getMessage());
210 } catch (\Exception $e) {
211 return $this->error_response($e->getMessage(), 500);
212 }
213 }
214
215 public function delete_item(WP_REST_Request $request)
216 {
217 try {
218 $result = $this->service->delete($this->getId($request));
219
220 if (!$result) {
221 return $this->error_response(__('Failed to delete item', 'yatra'), 500);
222 }
223
224 return $this->success_response([
225 'message' => __('Item deleted successfully', 'yatra'),
226 ]);
227 } catch (\Exception $e) {
228 return $this->error_response($e->getMessage(), 500);
229 }
230 }
231
232 private function prepareItem($item): array
233 {
234 $prepared = (array) $item;
235
236 // For unified ClassificationsTable, items have parent_id = item type ID
237 if (!empty($prepared['parent_id'])) {
238 $prepared['type_id'] = (int) $prepared['parent_id'];
239 }
240
241 // Get item type info
242 if (!empty($prepared['type_id'])) {
243 $type = $this->itemTypeRepository->find((int) $prepared['type_id']);
244
245 if ($type) {
246 $prepared['type_name'] = esc_html($type->name);
247
248 if (!empty($type->icon)) {
249 $icon_data = maybe_unserialize($type->icon);
250 if (is_array($icon_data) && isset($icon_data['value'])) {
251 $prepared['type_icon'] = $icon_data['value'];
252 if (
253 isset($icon_data['type'], $icon_data['provider'])
254 && $icon_data['type'] === 'icon'
255 ) {
256 $p = sanitize_key((string) $icon_data['provider']);
257 if (in_array($p, ['fa-solid', 'fa-regular'], true)) {
258 $prepared['type_icon_provider'] = $p;
259 }
260 }
261 } elseif (is_string($type->icon)) {
262 $prepared['type_icon'] = $type->icon;
263 }
264 }
265 } else {
266 // If type not found, set unknown
267 $prepared['type_name'] = __('Unknown', 'yatra');
268 }
269 } else {
270 // If no type_id, set unknown
271 $prepared['type_name'] = __('Unknown', 'yatra');
272 }
273
274 if (!empty($prepared['created_by'])) {
275 $user = get_userdata((int) $prepared['created_by']);
276 $prepared['created_by_name'] = $user ? esc_html($user->display_name) : null;
277 }
278
279 if (!empty($prepared['updated_by'])) {
280 $user = get_userdata((int) $prepared['updated_by']);
281 $prepared['updated_by_name'] = $user ? esc_html($user->display_name) : null;
282 }
283
284 $prepared['usage_count'] = $this->repository->countUsage((int) $prepared['id']);
285
286 return $prepared;
287 }
288 }
289