Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 198 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
ShortcutCategoryController | |
0.00% |
0 / 198 |
|
0.00% |
0 / 7 |
930 | |
0.00% |
0 / 1 |
create | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
30 | |||
update | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
30 | |||
list | |
0.00% |
0 / 92 |
|
0.00% |
0 / 1 |
2 | |||
details | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
delete | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
42 | |||
dependency | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
nestCategories | |
0.00% |
0 / 47 |
|
0.00% |
0 / 1 |
72 |
1 | <?php |
2 | |
3 | namespace App\Http\Controllers\v1; |
4 | |
5 | use App\Http\Controllers\Controller; |
6 | use App\Http\Helpers\ChangeManagement\ShortcutCategory\Move; |
7 | use App\Http\Helpers\ChangeManagement\ShortcutCategory\Remove; |
8 | use App\Http\Models\Shortcut; |
9 | use App\Http\Models\ShortcutCategory; |
10 | use App\Http\Models\ShortcutSubCategoryLv1; |
11 | use App\Http\Models\ShortcutSubCategoryLv1Position; |
12 | use App\Http\Models\ShortcutSubCategoryLv2; |
13 | use App\Http\Models\ShortcutSubCategoryLv2Position; |
14 | use App\Http\Requests\ShortcutCategoryFormRequest; |
15 | use App\Http\Services\ShortcutCategoryPositionService; |
16 | use App\Http\Services\ShortcutCategoryPositionServiceLv1; |
17 | use App\Http\Services\ShortcutCategoryPositionServiceLv2; |
18 | use App\Http\Services\ShortcutResolveService; |
19 | use Illuminate\Http\JsonResponse; |
20 | use Illuminate\Http\Request; |
21 | use Illuminate\Support\Facades\DB; |
22 | use Illuminate\Support\Facades\Log; |
23 | |
24 | class ShortcutCategoryController extends Controller |
25 | { |
26 | public function create(ShortcutCategoryFormRequest $request): JsonResponse |
27 | { |
28 | $data = $request->validated(); |
29 | $userId = $request->user()->getKey(); |
30 | $data['user_id'] = $userId; |
31 | $data['is_default'] = false; |
32 | |
33 | // If a subcategory and containing the parent category |
34 | if ($request['category_id'] && $request['category_id'] != '') { |
35 | $data['category_id'] = $request['category_id']; |
36 | |
37 | // if sub_categories_lv1 is included too will create sub_categories_lv2 |
38 | if ($request['sub_categories_lv1'] && $request['sub_categories_lv1'] != '') { |
39 | $data['sub_categories_lv1'] = $request['sub_categories_lv1']; |
40 | $result = ShortcutSubCategoryLv2::create($data); |
41 | $updateArray = ['sub_categories_lv2' => $result['_id']]; |
42 | ShortcutSubCategoryLv1::where('_id', $request['sub_categories_lv1'])->push($updateArray); |
43 | ShortcutSubCategoryLv2Position::updateOrCreate(['user_id' => $userId], ['user_id' => $userId]); |
44 | $obj = new ShortcutCategoryPositionServiceLv2(); |
45 | $obj->updateCategoryPosition($userId, $result['_id']); |
46 | } else { |
47 | $result = ShortcutSubCategoryLv1::create($data); |
48 | $updateArray = ['sub_categories_lv1' => $result['_id']]; |
49 | ShortcutCategory::where('_id', $request['category_id'])->push($updateArray); |
50 | ShortcutSubCategoryLv1Position::updateOrCreate(['user_id' => $userId], ['user_id' => $userId]); |
51 | $obj = new ShortcutCategoryPositionServiceLv1(); |
52 | $obj->updateCategoryPosition($userId, $result['_id']); |
53 | } |
54 | } else { |
55 | $result = ShortcutCategory::create($data); |
56 | $obj = new ShortcutCategoryPositionService(); |
57 | $obj->updateCategoryPosition($userId, $result['_id']); |
58 | } |
59 | |
60 | return response()->json($result['_id']); |
61 | } |
62 | |
63 | public function update(ShortcutCategoryFormRequest $request, $categoryId): JsonResponse |
64 | { |
65 | $data = $request->validated(); |
66 | $userId = $request->user()->getKey(); |
67 | $data['user_id'] = $userId; |
68 | $data['is_default'] = false; |
69 | |
70 | //If there's a nesting request retrieve the data and update relations. |
71 | if (filled($request->category_id) || filled($request->sub_categories_lv1)) { |
72 | |
73 | $sourceCategoryType = $data['source_category_type']; |
74 | unset($data['source_category_type']); |
75 | |
76 | if (filled($request->sub_categories_lv1)) { |
77 | |
78 | $result = $this->nestCategories($categoryId, $sourceCategoryType, $request->sub_categories_lv1, 'sub_categories_lv1', $data); |
79 | } else { |
80 | |
81 | $result = $this->nestCategories($categoryId, $sourceCategoryType, $request->category_id, 'category_id', $data); |
82 | } |
83 | } else { |
84 | |
85 | //If there's no nesting request, just update the name of the category |
86 | |
87 | $result = match ($data['source_category_type']) { |
88 | 'category' => ShortcutCategory::find($categoryId), |
89 | 'sub_categories_lv1' => ShortcutSubCategoryLv1::find($categoryId), |
90 | 'sub_categories_lv2' => ShortcutSubCategoryLv2::find($categoryId) |
91 | }; |
92 | |
93 | if ($result) { |
94 | $result->update($data); |
95 | } else { |
96 | $result = false; |
97 | } |
98 | } |
99 | |
100 | return response()->json((bool) $result); |
101 | } |
102 | |
103 | public function list(Request $request) |
104 | { |
105 | $userId = $request->user()->getKey(); |
106 | |
107 | $result = ShortcutCategory::raw(function ($collection) use ($userId) { |
108 | return $collection->aggregate([ |
109 | ['$match' => ['user_id' => $userId]], // Filter by logged in user |
110 | ['$lookup' => [ |
111 | 'from' => 'shortcut_sub_categories_lv1', // Perform a left outer join on the shortcut_sub_categories_lv1 collection |
112 | 'let' => ['id' => ['$toString' => '$_id']], // Convert mongo id to string to allow for join comparison |
113 | 'pipeline' => [ |
114 | ['$match' => [ |
115 | '$expr' => [ |
116 | '$eq' => ['$$id', '$category_id'] // Join comparison |
117 | ] |
118 | ]], |
119 | ['$lookup' => [ // Repeat the last three comments for the shortcut_sub_categories_lv2 |
120 | 'from' => 'shortcut_sub_categories_lv2', |
121 | 'let' => ['subId' => ['$toString' => '$_id']], |
122 | 'pipeline' => [ |
123 | [ |
124 | '$match' => [ |
125 | '$expr' => [ |
126 | '$eq' => ['$$subId', '$sub_categories_lv1'] |
127 | ] |
128 | ] |
129 | ], |
130 | ['$lookup' => [ |
131 | 'from' => 'shortcuts', |
132 | 'let' => ['subSubCatId' => ['$toString' => '$_id']], |
133 | 'pipeline' => [ |
134 | ['$match' => [ |
135 | '$expr' => ['$eq' => ['$$subSubCatId', '$sub_categories_lv2_id']] |
136 | ]] |
137 | ], |
138 | 'as' => 'shortcuts' // Store the matching shortcuts in an array named 'shortcuts' |
139 | ]], |
140 | [ |
141 | '$addFields' => [ |
142 | 'id' => ['$toString' => '$_id'], // Convert mongo object id to string |
143 | 'updated_at' => [ |
144 | '$dateToString' => [ |
145 | 'format' => '%Y-%m-%dT%H:%M:%S.%LZ', |
146 | 'date' => '$updated_at' |
147 | ] |
148 | ], |
149 | 'created_at' => [ |
150 | '$dateToString' => [ |
151 | 'format' => '%Y-%m-%dT%H:%M:%S.%LZ', |
152 | 'date' => '$created_at' |
153 | ] |
154 | ], //Make the updated_at and created_at fields in carbon form for frontend utilisation |
155 | 'shortcuts_count' => ['$size' => '$shortcuts'] // Calculate the size of the 'shortcuts' array |
156 | ] |
157 | ], |
158 | ['$unset' => 'shortcuts'] // Remove the 'shortcuts' array as it's no longer needed |
159 | ], |
160 | 'as' => 'sub_category_lv2' |
161 | ]], |
162 | ['$lookup' => [ |
163 | 'from' => 'shortcuts', |
164 | 'let' => ['subCatId' => ['$toString' => '$_id']], |
165 | 'pipeline' => [ |
166 | ['$match' => [ |
167 | '$expr' => ['$eq' => ['$$subCatId', '$sub_categories_lv1_id']] |
168 | ]] |
169 | ], |
170 | 'as' => 'shortcuts' // Store the matching shortcuts in an array named 'shortcuts' |
171 | ]], |
172 | [ |
173 | '$addFields' => [ |
174 | 'id' => ['$toString' => '$_id'], |
175 | 'updated_at' => [ |
176 | '$dateToString' => [ |
177 | 'format' => '%Y-%m-%dT%H:%M:%S.%LZ', |
178 | 'date' => '$updated_at' |
179 | ] |
180 | ], |
181 | 'created_at' => [ |
182 | '$dateToString' => [ |
183 | 'format' => '%Y-%m-%dT%H:%M:%S.%LZ', |
184 | 'date' => '$created_at' |
185 | ] |
186 | ], //Make the updated_at and created_at fields in carbon form for frontend utilisation |
187 | 'shortcuts_count' => ['$size' => '$shortcuts'] // Calculate the size of the 'shortcuts' array |
188 | ] |
189 | ], |
190 | ['$unset' => 'shortcuts'] // Remove the 'shortcuts' array as it's no longer needed |
191 | ], |
192 | 'as' => 'sub_category_lv1' |
193 | ]], |
194 | ['$sort' => ['is_default' => -1, 'seq_id' => 1]] // sort the result |
195 | ]); |
196 | }); |
197 | |
198 | return response()->json($result); |
199 | } |
200 | |
201 | public function details(Request $request, $categoryId) |
202 | { |
203 | $searchArray = ['_id' => $categoryId]; |
204 | $category = ShortcutCategory::where($searchArray)->first(); |
205 | $category['shortcuts_count'] = $category->shortcuts()->count(); |
206 | return response()->json($category); |
207 | } |
208 | |
209 | public function delete(ShortcutCategoryFormRequest $request, ShortcutResolveService $shortcut_service, $id): JsonResponse |
210 | { |
211 | $categoryId = $request->has('type') && $request->type === 'move' ? $request->category_id : ShortcutCategory::where('is_default', true)->value('_id'); |
212 | |
213 | if (! ($request->has('type') && $request->type === 'move') && ! $categoryId) { |
214 | abort(422, 'You do not have default category'); |
215 | } |
216 | |
217 | $shortcut_service->{'resolve_' . $request->category_type}($id, $categoryId); |
218 | |
219 | return response()->json('Deleted successfully', 202); |
220 | } |
221 | |
222 | public function dependency(Request $request, $categoryId, $type) |
223 | { |
224 | switch ($type) { |
225 | case 'remove': |
226 | $obj = new Remove(); |
227 | return response()->json($obj->dependency($categoryId)); |
228 | case 'move': |
229 | $obj = new Move(); |
230 | return response()->json($obj->dependency($categoryId)); |
231 | default: |
232 | return response()->json([]); |
233 | } |
234 | } |
235 | |
236 | private function nestCategories($sourceCategoryId, $sourceType, $destinationCategoryId, $destinationType, $data) |
237 | { |
238 | $sourceCategory = match ($sourceType) { |
239 | 'category' => ShortcutCategory::find($sourceCategoryId), |
240 | 'sub_categories_lv1' => ShortcutSubCategoryLv1::find($sourceCategoryId), |
241 | 'sub_categories_lv2' => ShortcutSubCategoryLv2::find($sourceCategoryId) |
242 | }; |
243 | |
244 | $destinationCategory = match ($destinationType) { |
245 | 'category_id' => ShortcutCategory::find($destinationCategoryId), |
246 | 'sub_categories_lv1' => ShortcutSubCategoryLv1::find($destinationCategoryId), |
247 | }; |
248 | |
249 | // sub_category_lv2 nested under sub_category_lv1 | sub_category_lv1 nested under category |
250 | |
251 | if ( |
252 | ($sourceType == 'sub_categories_lv2' && $destinationType == 'sub_categories_lv1') || |
253 | (($sourceType == 'sub_categories_lv1' && $destinationType == 'category_id')) |
254 | ) { |
255 | $sourceCategory->update($data); |
256 | |
257 | $searchArray = match ($sourceType) { |
258 | //'category' => ['category_id' => $sourceCategoryId], |
259 | 'sub_categories_lv1' => ['sub_categories_lv1_id' => $sourceCategoryId], |
260 | 'sub_categories_lv2' => ['sub_categories_lv2_id' => $sourceCategoryId] |
261 | }; |
262 | |
263 | $updateArray = match ($destinationType) { |
264 | 'category_id' => [ |
265 | 'category_id' => $destinationCategory->id, |
266 | ], |
267 | 'sub_categories_lv1' => [ |
268 | 'category_id' => $destinationCategory->category_id, |
269 | 'sub_categories_lv1_id' => $destinationCategory->id, |
270 | ] |
271 | }; |
272 | |
273 | Shortcut::where($searchArray)->update($updateArray); |
274 | return true; |
275 | // sub_category_lv2 nested under category |
276 | } else if (($sourceType == 'sub_categories_lv2' && $destinationType == 'category_id')) { |
277 | |
278 | $session = DB::getMongoClient()->startSession(); |
279 | $session->startTransaction(); |
280 | |
281 | try { |
282 | // extract the content of the sub_cat_lv2 and create it as a sub_cat_lv1. preserve the id so that references can maintain connnection |
283 | $data = array_merge($sourceCategory->getAttributes(), $data); |
284 | $shortcutSubCategoryLv1 = ShortcutSubCategoryLv1::create($data); |
285 | |
286 | ShortcutSubCategoryLv1Position::updateOrCreate(['user_id' => $data['user_id']], ['user_id' => $data['user_id']]); |
287 | (new ShortcutCategoryPositionServiceLv1())->updateCategoryPosition($data['user_id'], $shortcutSubCategoryLv1->id); |
288 | |
289 | // update all the shortcuts that were previously connected to the sub_cat_lv2 so they can become connected to the sub_cat_lv1 |
290 | Shortcut::where('sub_categories_lv2_id', $sourceCategoryId)->update([ |
291 | 'category_id' => $shortcutSubCategoryLv1->category_id, |
292 | 'sub_categories_lv1_id' => $shortcutSubCategoryLv1->id, |
293 | 'sub_categories_lv2_id' => '' |
294 | ]); |
295 | |
296 | // delete the sub_cat_lv2 |
297 | $sourceCategory->delete(); |
298 | |
299 | $session->commitTransaction(); |
300 | |
301 | return true; |
302 | } catch (\Exception $e) { |
303 | Log::error($e->getMessage()); |
304 | $session->abortTransaction(); |
305 | |
306 | return false; |
307 | } |
308 | } else { |
309 | // Don't permit other kinds of nesting |
310 | // abort(422, 'Invalid nesting'); |
311 | return false; |
312 | } |
313 | } |
314 | } |