From a83fb1d8d32975f1006e3888eddd1938fcf0e50b Mon Sep 17 00:00:00 2001 From: baodev0 Date: Tue, 4 Aug 2026 17:18:15 +0700 Subject: [PATCH] update --- .DS_Store | Bin 10244 -> 10244 bytes app/.DS_Store | Bin 10244 -> 10244 bytes app/Services/.DS_Store | Bin 6148 -> 6148 bytes database/.DS_Store | Bin 6148 -> 6148 bytes database/seeders/RolesAndPermissions.php | 7 ++ .../Controllers/Api/Admin/MenuController.php | 89 +++++++++++++++++ .../Api/Admin/MenuItemController.php | 93 ++++++++++++++++++ .../Http/Requests/StoreMenuItemRequest.php | 23 +++++ .../App/Http/Requests/StoreMenuRequest.php | 21 ++++ .../App/Http/Resources/MenuItemResource.php | 22 +++++ .../Menu/App/Http/Resources/MenuResource.php | 20 ++++ modules/Menu/App/Models/Menu.php | 21 ++++ modules/Menu/App/Models/MenuItem.php | 21 ++++ .../App/Providers/MenuServiceProvider.php | 37 +++++++ .../App/Providers/RouteServiceProvider.php | 29 ++++++ ...26_07_27_120000_create_nav_menus_table.php | 22 +++++ ..._27_120001_create_nav_menu_items_table.php | 25 +++++ modules/Menu/composer.json | 31 ++++++ modules/Menu/config/config.php | 5 + modules/Menu/module.json | 11 +++ modules/Menu/routes/api.php | 41 ++++++++ modules_statuses.json | 3 +- storage/.DS_Store | Bin 6148 -> 6148 bytes tests/.DS_Store | Bin 6148 -> 6148 bytes 24 files changed, 520 insertions(+), 1 deletion(-) create mode 100644 modules/Menu/App/Http/Controllers/Api/Admin/MenuController.php create mode 100644 modules/Menu/App/Http/Controllers/Api/Admin/MenuItemController.php create mode 100644 modules/Menu/App/Http/Requests/StoreMenuItemRequest.php create mode 100644 modules/Menu/App/Http/Requests/StoreMenuRequest.php create mode 100644 modules/Menu/App/Http/Resources/MenuItemResource.php create mode 100644 modules/Menu/App/Http/Resources/MenuResource.php create mode 100644 modules/Menu/App/Models/Menu.php create mode 100644 modules/Menu/App/Models/MenuItem.php create mode 100644 modules/Menu/App/Providers/MenuServiceProvider.php create mode 100644 modules/Menu/App/Providers/RouteServiceProvider.php create mode 100644 modules/Menu/Database/migrations/2026_07_27_120000_create_nav_menus_table.php create mode 100644 modules/Menu/Database/migrations/2026_07_27_120001_create_nav_menu_items_table.php create mode 100644 modules/Menu/composer.json create mode 100644 modules/Menu/config/config.php create mode 100644 modules/Menu/module.json create mode 100644 modules/Menu/routes/api.php diff --git a/.DS_Store b/.DS_Store index c579f32909581bc2097848aa63ab0453423ae5f0..359e8432ca23b9d86c4fda44693bd92c6abe065d 100644 GIT binary patch delta 737 zcmZn(XbISmBpA=>vMiW^fq{iVk0G5Qlc6Lx-^C>Mb;`bcLE@xs@n9M0D$IQsAH(5(khJB4!QD_j?iOIf_ zvT$~xq&%a+ErLsuz@{T#*hjO?G%ui$fm6oepsEr1PyHz fH3$zv)l8O@kz@4TSa_a!GrIx@E14nA3J!4q$5+#7 delta 739 zcmZn(XbISmBpA;gQ{c|Pz`(+w$B@pD$xxD;@8Xh_lb-|>dEE z54H|X4Z>2Wn#qwO&P)j(C(jcpWa2xpSx|H*Bh#$alh26BvH!H}e(3P^_~egb@$RuB7wnhf}s#J~u delta 296 zcmZn(XbIS`R3wfsMVWztfrY_?p#%sEa`RnWl5+BsfMOi;SWY^gK7QO0RXzo;d_jg` zaB_Zb0ZB)qF;Q%yo+2a9#DLw41(+Bac_#BPey(R{@MOqkC}7BEC}JpKD9%YY z3{K9^EnonH+C@MLO+{|Li%U{YeiBfI;{vB`UfP%Aj@VSC5TU9dgBRJl37Z+2YFIY2 fbMSKj-3#P=XP(S2V#&eCzyL%H44VT)wlD(##WgUv delta 66 zcmZoMXfc=|#>B`mF;Q%yo+6MA*v-f>nTP4~=Bdm@EE@}^F>Yq(;O79U*gTQ>JM(0I T5lapRAYf!*VA>oYvV|D{V$cw( diff --git a/database/.DS_Store b/database/.DS_Store index 66a4dbb08c77d1717c266bcd4c6c447ac3ba0355..fe224614325c7b77f8b2fca6d2dfff17fe1b8a00 100644 GIT binary patch delta 63 zcmZoMXffDuk%^fp;?*Q(smbq{xY%_%rlgv2otXTeNfn7L$zPCR7@VA+TfhJU90i+$ InKz060K<|LtpET3 delta 63 zcmZoMXffDuk%^hHG=CDa)Z}+eTwithCount('items')->orderBy('key')->get(); + + return response()->json([ + 'success' => true, + 'data' => MenuResource::collection($menus), + ]); + } + + public function show(int $id): JsonResponse + { + $menu = Menu::withCount('items')->find($id); + + if (! $menu) { + return response()->json([ + 'success' => false, + 'message' => 'Không tìm thấy menu', + ], 404); + } + + return response()->json([ + 'success' => true, + 'data' => MenuResource::make($menu), + ]); + } + + public function store(StoreMenuRequest $request): JsonResponse + { + $menu = Menu::create($request->validated()); + + return response()->json([ + 'success' => true, + 'message' => 'Tạo menu thành công', + 'data' => MenuResource::make($menu), + ], 201); + } + + public function update(int $id, StoreMenuRequest $request): JsonResponse + { + $menu = Menu::find($id); + + if (! $menu) { + return response()->json([ + 'success' => false, + 'message' => 'Không tìm thấy menu', + ], 404); + } + + $menu->update($request->validated()); + + return response()->json([ + 'success' => true, + 'message' => 'Cập nhật menu thành công', + 'data' => MenuResource::make($menu), + ]); + } + + public function destroy(int $id): JsonResponse + { + $menu = Menu::find($id); + + if (! $menu) { + return response()->json([ + 'success' => false, + 'message' => 'Không tìm thấy menu', + ], 404); + } + + $menu->delete(); + + return response()->json([ + 'success' => true, + 'message' => 'Xoá menu thành công', + ]); + } +} diff --git a/modules/Menu/App/Http/Controllers/Api/Admin/MenuItemController.php b/modules/Menu/App/Http/Controllers/Api/Admin/MenuItemController.php new file mode 100644 index 0000000..6f5fa5a --- /dev/null +++ b/modules/Menu/App/Http/Controllers/Api/Admin/MenuItemController.php @@ -0,0 +1,93 @@ +when($request->integer('menu_id'), fn ($q, $menuId) => $q->where('menu_id', $menuId)) + ->orderBy('id') + ->get(); + + return response()->json([ + 'success' => true, + 'data' => MenuItemResource::collection($items), + ]); + } + + public function show(int $id): JsonResponse + { + $item = MenuItem::find($id); + + if (! $item) { + return response()->json([ + 'success' => false, + 'message' => 'Không tìm thấy menu item', + ], 404); + } + + return response()->json([ + 'success' => true, + 'data' => MenuItemResource::make($item), + ]); + } + + public function store(StoreMenuItemRequest $request): JsonResponse + { + $item = MenuItem::create($request->validated()); + + return response()->json([ + 'success' => true, + 'message' => 'Tạo menu item thành công', + 'data' => MenuItemResource::make($item), + ], 201); + } + + public function update(int $id, StoreMenuItemRequest $request): JsonResponse + { + $item = MenuItem::find($id); + + if (! $item) { + return response()->json([ + 'success' => false, + 'message' => 'Không tìm thấy menu item', + ], 404); + } + + $item->update($request->validated()); + + return response()->json([ + 'success' => true, + 'message' => 'Cập nhật menu item thành công', + 'data' => MenuItemResource::make($item), + ]); + } + + public function destroy(int $id): JsonResponse + { + $item = MenuItem::find($id); + + if (! $item) { + return response()->json([ + 'success' => false, + 'message' => 'Không tìm thấy menu item', + ], 404); + } + + $item->delete(); + + return response()->json([ + 'success' => true, + 'message' => 'Xoá menu item thành công', + ]); + } +} diff --git a/modules/Menu/App/Http/Requests/StoreMenuItemRequest.php b/modules/Menu/App/Http/Requests/StoreMenuItemRequest.php new file mode 100644 index 0000000..49ce0d2 --- /dev/null +++ b/modules/Menu/App/Http/Requests/StoreMenuItemRequest.php @@ -0,0 +1,23 @@ + ['required', 'integer', 'exists:nav_menus,id'], + 'label' => ['required', 'string', 'max:255'], + 'url' => ['required', 'string', 'max:255'], + 'icon' => ['nullable', 'string', 'max:255'], + ]; + } +} diff --git a/modules/Menu/App/Http/Requests/StoreMenuRequest.php b/modules/Menu/App/Http/Requests/StoreMenuRequest.php new file mode 100644 index 0000000..b9e1c96 --- /dev/null +++ b/modules/Menu/App/Http/Requests/StoreMenuRequest.php @@ -0,0 +1,21 @@ + ['required', 'string', 'max:255', Rule::unique('nav_menus', 'key')->ignore($this->route('id'))], + ]; + } +} diff --git a/modules/Menu/App/Http/Resources/MenuItemResource.php b/modules/Menu/App/Http/Resources/MenuItemResource.php new file mode 100644 index 0000000..51b18f8 --- /dev/null +++ b/modules/Menu/App/Http/Resources/MenuItemResource.php @@ -0,0 +1,22 @@ + $this->id, + 'menu_id' => $this->menu_id, + 'label' => $this->label, + 'url' => $this->url, + 'icon' => $this->icon, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/modules/Menu/App/Http/Resources/MenuResource.php b/modules/Menu/App/Http/Resources/MenuResource.php new file mode 100644 index 0000000..12d9991 --- /dev/null +++ b/modules/Menu/App/Http/Resources/MenuResource.php @@ -0,0 +1,20 @@ + $this->id, + 'key' => $this->key, + 'items_count' => $this->when(isset($this->items_count), fn () => (int) $this->items_count), + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/modules/Menu/App/Models/Menu.php b/modules/Menu/App/Models/Menu.php new file mode 100644 index 0000000..0b3350e --- /dev/null +++ b/modules/Menu/App/Models/Menu.php @@ -0,0 +1,21 @@ +hasMany(MenuItem::class); + } +} diff --git a/modules/Menu/App/Models/MenuItem.php b/modules/Menu/App/Models/MenuItem.php new file mode 100644 index 0000000..5a11cae --- /dev/null +++ b/modules/Menu/App/Models/MenuItem.php @@ -0,0 +1,21 @@ +belongsTo(Menu::class); + } +} diff --git a/modules/Menu/App/Providers/MenuServiceProvider.php b/modules/Menu/App/Providers/MenuServiceProvider.php new file mode 100644 index 0000000..c003ab2 --- /dev/null +++ b/modules/Menu/App/Providers/MenuServiceProvider.php @@ -0,0 +1,37 @@ +registerConfig(); + $this->registerMigrations(); + $this->app->register(RouteServiceProvider::class); + } + + public function register(): void + { + // + } + + protected function registerConfig(): void + { + $this->mergeConfigFrom( + module_path($this->moduleName, 'config/config.php'), + $this->moduleNameLower + ); + } + + protected function registerMigrations(): void + { + $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/migrations')); + } +} diff --git a/modules/Menu/App/Providers/RouteServiceProvider.php b/modules/Menu/App/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..90500be --- /dev/null +++ b/modules/Menu/App/Providers/RouteServiceProvider.php @@ -0,0 +1,29 @@ +mapApiRoutes(); + } + + protected function mapApiRoutes(): void + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->moduleNamespace) + ->group(module_path('Menu', '/routes/api.php')); + } +} diff --git a/modules/Menu/Database/migrations/2026_07_27_120000_create_nav_menus_table.php b/modules/Menu/Database/migrations/2026_07_27_120000_create_nav_menus_table.php new file mode 100644 index 0000000..d99dd5b --- /dev/null +++ b/modules/Menu/Database/migrations/2026_07_27_120000_create_nav_menus_table.php @@ -0,0 +1,22 @@ +id(); + $table->string('key')->unique(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('nav_menus'); + } +}; diff --git a/modules/Menu/Database/migrations/2026_07_27_120001_create_nav_menu_items_table.php b/modules/Menu/Database/migrations/2026_07_27_120001_create_nav_menu_items_table.php new file mode 100644 index 0000000..acf9e9c --- /dev/null +++ b/modules/Menu/Database/migrations/2026_07_27_120001_create_nav_menu_items_table.php @@ -0,0 +1,25 @@ +id(); + $table->foreignId('menu_id')->constrained('nav_menus')->cascadeOnDelete(); + $table->string('label'); + $table->string('url'); + $table->string('icon')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('nav_menu_items'); + } +}; diff --git a/modules/Menu/composer.json b/modules/Menu/composer.json new file mode 100644 index 0000000..bf421af --- /dev/null +++ b/modules/Menu/composer.json @@ -0,0 +1,31 @@ +{ + "name": "nwidart/menu", + "description": "", + "authors": [ + { + "name": "Nicolas Widart", + "email": "n.widart@gmail.com" + } + ], + "extra": { + "laravel": { + "providers": [], + "aliases": { + + } + } + }, + "autoload": { + "psr-4": { + "Modules\\Menu\\": "", + "Modules\\Menu\\App\\": "App/", + "Modules\\Menu\\Database\\Factories\\": "Database/Factories/", + "Modules\\Menu\\Database\\Seeders\\": "Database/Seeders/" + } + }, + "autoload-dev": { + "psr-4": { + "Modules\\Menu\\Tests\\": "tests/" + } + } +} diff --git a/modules/Menu/config/config.php b/modules/Menu/config/config.php new file mode 100644 index 0000000..1cccead --- /dev/null +++ b/modules/Menu/config/config.php @@ -0,0 +1,5 @@ + 'Menu', +]; diff --git a/modules/Menu/module.json b/modules/Menu/module.json new file mode 100644 index 0000000..a07641f --- /dev/null +++ b/modules/Menu/module.json @@ -0,0 +1,11 @@ +{ + "name": "Menu", + "alias": "menu", + "description": "Quan ly Menu va Menu Item", + "keywords": [], + "priority": 0, + "providers": [ + "Modules\\Menu\\App\\Providers\\MenuServiceProvider" + ], + "files": [] +} diff --git a/modules/Menu/routes/api.php b/modules/Menu/routes/api.php new file mode 100644 index 0000000..cfcbac8 --- /dev/null +++ b/modules/Menu/routes/api.php @@ -0,0 +1,41 @@ +group(function () { + Route::prefix('administrator') + ->middleware('api.auth:admin') + ->group(function () { + Route::prefix('menus') + ->controller(MenuController::class) + ->group(function () { + Route::get('/', 'index')->middleware('perm:menu.view'); + Route::post('/', 'store')->middleware('perm:menu.create'); + Route::get('{id}', 'show')->middleware('perm:menu.view'); + Route::put('{id}', 'update')->middleware('perm:menu.edit'); + Route::delete('{id}', 'destroy')->middleware('perm:menu.destroy'); + }); + + Route::prefix('menu-items') + ->controller(MenuItemController::class) + ->group(function () { + Route::get('/', 'index')->middleware('perm:menu.view'); + Route::post('/', 'store')->middleware('perm:menu.create'); + Route::get('{id}', 'show')->middleware('perm:menu.view'); + Route::put('{id}', 'update')->middleware('perm:menu.edit'); + Route::delete('{id}', 'destroy')->middleware('perm:menu.destroy'); + }); + }); + }); diff --git a/modules_statuses.json b/modules_statuses.json index 6663f72..b6232d8 100644 --- a/modules_statuses.json +++ b/modules_statuses.json @@ -1,3 +1,4 @@ { - "DomainFluctuation": true + "DomainFluctuation": true, + "Menu": true } diff --git a/storage/.DS_Store b/storage/.DS_Store index 5e70cc7732863660a5adc89f51a90814a4a8e1e8..bb9a9d2e773a850b6b76cfc14bd26656f97db0e5 100644 GIT binary patch delta 457 zcmZoMXfc@J&nUYwU^g?P>|_HLk;w`yvsf5k&9R!ik43D$Cwt4OPRaI<$W0PQyI4heL%ynY&TsBEKdoP<5Q^|#ig>swOIsWnk0G)_> AiU0rr delta 185 zcmZoMXfc@J&nUVvU^g?P=wt&Hk;w`yvsf6W-}Iimk3}p@>{HF{*$&4Y85kIt84?)^ z7z%RpQ(TgA@{@of9GJ2N8HT~h`MCu^Sq6qV6F?+XUs-TbUQT{qI#7gh@-EidldrNV zFf-g~p8SKYoQdhfSu&+poi7vQ$eDYd$NjUo~yA;#of{lfGjGNgx H{_+C=d}}-P diff --git a/tests/.DS_Store b/tests/.DS_Store index dde8d2de630b0bb9dfcfbe13398934587043549a..572cc6b26734b07411949b19ac4c0f88e494890a 100644 GIT binary patch delta 71 zcmZoMXffEJ!^9L;K3R`RPS3?&Su3`Gp7x%nwBNjdpR VKp76Gs>zj1ii`rAXESAr0sy=B6bJwS