diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 0000000..71c0fac
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,17 @@
+name: Laravel.php Menu
+
+on: push
+
+jobs:
+ cd:
+ runs-on: ubuntu-latest
+ steps:
+ - name: cd
+ uses: tripteki/cd-package@1.0.0
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ repotoken: ${{ secrets.REPOSITORY_TOKEN }}
+ repouser: tripteki
+ repository: https://packagist.org
+ language: php
+ artifact: composer.json
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..061b3a5
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Trip Teknologi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7f421a8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,73 @@
+
Menu
+
+This package provides implementation of Menu in repository pattern for Lumen and Laravel besides REST API starterpack of admin management with no intervention to codebase and keep clean.
+
+Getting Started
+---
+
+Installation :
+
+```
+composer require tripteki/laravelphp-menu
+```
+
+How to use it :
+
+- Put `Tripteki\Menu\Providers\MenuServiceProvider` to service provider configuration list.
+
+- Put `Tripteki\Menu\Providers\MenuServiceProvider::ignoreMigrations()` into `register` provider, then publish migrations file into your project's directory with running (optionally) :
+
+```
+php artisan vendor:publish --tag=tripteki-laravelphp-menu-migrations
+```
+
+- Migrate.
+
+```
+php artisan migrate
+```
+
+- Sample :
+
+```php
+use Tripteki\Menu\Contracts\Repository\Admin\IMenuAdminRepository;
+use Tripteki\Menu\Contracts\Repository\IMenuRepository;
+
+$menuAdminRepository = app(IMenuAdminRepository::class);
+
+// $menuAdminRepository->create([ "platform" => "desktop", "route" => "/ads", "nth" => 0, "title" => "ads_gallery", "icon" => "md-gallery", "description" => "Gallery", ]); //
+// $menuAdminRepository->delete("identifier"); //
+// $menuAdminRepository->update("identifier", [ "platform" => "desktop", "route" => "/ads", "nth" => 1, "title" => "ads_gallery", "icon" => "md-gallery", "description" => "Gallery", ]); //
+// $menuAdminRepository->activate("identifier"); //
+// $menuAdminRepository->deactivate("identifier"); //
+// $menuAdminRepository->get("identifier"); //
+// $menuAdminRepository->all(); //
+
+$repository = app(IMenuRepository::class);
+
+// $repository->get("desktop", "/ads", 5); //
+// $repository->all("web", "/ads"); //
+// $repository->all("mobile", "/ads"); //
+// $repository->all("desktop", "/ads"); //
+```
+
+- Generate swagger files into your project's directory with putting this into your annotation configuration (optionally) :
+
+```
+base_path("app/Http/Controllers/Menu")
+```
+
+```
+base_path("app/Http/Controllers/Admin/Menu")
+```
+
+Usage
+---
+
+`php artisan adminer:install:menu`
+
+Author
+---
+
+- Trip Teknologi ([@tripteki](https://linkedin.com/company/tripteki))
+- Hasby Maulana ([@hsbmaulana](https://linkedin.com/in/hsbmaulana))
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..4433435
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,55 @@
+{
+ "name": "tripteki/laravelphp-menu",
+ "version": "1.0.0",
+ "description": "Trip Teknologi's Laravel.php Menus",
+
+ "readme": "README.md",
+ "license": "MIT",
+ "authors": [ { "name": "Trip Teknologi", "email": "tripteki.company@gmail.com" } ],
+ "homepage": "https://github.com/tripteki/laravelphp-menu",
+ "support": { "issues": "https://github.com/tripteki/laravelphp-menu/issues" },
+
+ "require": {
+
+ "php": "^8.0.2",
+
+ "tripteki/laravelphp-repository": "^1.0.0",
+ "tripteki/laravelphp-helpers": "^1.0.0",
+ "tripteki/laravelphp-adminer": "^1.0.0",
+ "tripteki/laravelphp-import-export": "^1.0.0",
+ "tripteki/laravelphp-request-response-query": "^1.0.0"
+ },
+
+ "require-dev": {},
+
+ "suggest": {
+
+ "laravel/lumen-framework": "Required when using lumen framework (^9.0).",
+ "laravel/framework": "Required when using laravel framework (^9.0)."
+ },
+
+ "autoload": {
+
+ "psr-4": {
+
+ "Tripteki\\Menu\\": "src/"
+ }
+ },
+
+ "autoload-dev": {},
+
+ "extra": {
+
+ "laravel": {
+
+ "dont-discover": [],
+
+ "providers": [
+
+ "Tripteki\\Menu\\Providers\\MenuServiceProvider"
+ ],
+
+ "aliases": []
+ }
+ }
+}
diff --git a/database/migrations/2023_01_15_000001_create_menus_table.php b/database/migrations/2023_01_15_000001_create_menus_table.php
new file mode 100644
index 0000000..5a0d537
--- /dev/null
+++ b/database/migrations/2023_01_15_000001_create_menus_table.php
@@ -0,0 +1,39 @@
+uuid("id");
+
+ $table->string("platform");
+ $table->string("route");
+ $table->integer("nth")->default(0);
+ $table->string("title");
+ $table->string("icon")->nullable(true);
+ $table->text("description")->nullable(true);
+ $table->timestamps();
+ $table->softDeletes();
+
+ $table->primary("id");
+ $table->unique([ "platform", "route", "title", ]);
+ });
+ }
+
+ /**
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists("menus");
+ }
+};
diff --git a/src/Console/Commands/InstallCommand.php b/src/Console/Commands/InstallCommand.php
new file mode 100644
index 0000000..4f5b542
--- /dev/null
+++ b/src/Console/Commands/InstallCommand.php
@@ -0,0 +1,75 @@
+helper = $helper;
+ }
+
+ /**
+ * @return int
+ */
+ public function handle()
+ {
+ $this->installStack();
+
+ return 0;
+ }
+
+ /**
+ * @return int|null
+ */
+ protected function installStack()
+ {
+ (new Filesystem)->ensureDirectoryExists(base_path("routes/user"));
+ (new Filesystem)->ensureDirectoryExists(base_path("routes/admin"));
+ (new Filesystem)->copy(__DIR__."/../../../stubs/routes/user/menu.php", base_path("routes/user/menu.php"));
+ (new Filesystem)->copy(__DIR__."/../../../stubs/routes/admin/menu.php", base_path("routes/admin/menu.php"));
+ $this->helper->putRoute("api.php", "user/menu.php");
+ $this->helper->putRoute("api.php", "admin/menu.php");
+
+ (new Filesystem)->ensureDirectoryExists(app_path("Http/Controllers/Menu"));
+ (new Filesystem)->copyDirectory(__DIR__."/../../../stubs/app/Http/Controllers/Menu", app_path("Http/Controllers/Menu"));
+ (new Filesystem)->ensureDirectoryExists(app_path("Http/Requests/Menus"));
+ (new Filesystem)->copyDirectory(__DIR__."/../../../stubs/app/Http/Requests/Menus", app_path("Http/Requests/Menus"));
+ (new Filesystem)->ensureDirectoryExists(app_path("Http/Controllers/Admin/Menu"));
+ (new Filesystem)->copyDirectory(__DIR__."/../../../stubs/app/Http/Controllers/Admin/Menu", app_path("Http/Controllers/Admin/Menu"));
+ (new Filesystem)->ensureDirectoryExists(app_path("Imports/Menus"));
+ (new Filesystem)->copyDirectory(__DIR__."/../../../stubs/app/Imports/Menus", app_path("Imports/Menus"));
+ (new Filesystem)->ensureDirectoryExists(app_path("Exports/Menus"));
+ (new Filesystem)->copyDirectory(__DIR__."/../../../stubs/app/Exports/Menus", app_path("Exports/Menus"));
+ (new Filesystem)->ensureDirectoryExists(app_path("Http/Requests/Admin/Menus"));
+ (new Filesystem)->copyDirectory(__DIR__."/../../../stubs/app/Http/Requests/Admin/Menus", app_path("Http/Requests/Admin/Menus"));
+ (new Filesystem)->ensureDirectoryExists(app_path("Http/Responses"));
+
+ $this->info("Adminer Menu scaffolding installed successfully.");
+ }
+};
diff --git a/src/Contracts/Repository/Admin/IMenuAdminRepository.php b/src/Contracts/Repository/Admin/IMenuAdminRepository.php
new file mode 100644
index 0000000..6f89a81
--- /dev/null
+++ b/src/Contracts/Repository/Admin/IMenuAdminRepository.php
@@ -0,0 +1,14 @@
+restore();
+ }
+
+ /**
+ * @return void
+ */
+ public function deactivate()
+ {
+ $this->delete();
+ }
+};
diff --git a/src/Providers/MenuServiceProvider.php b/src/Providers/MenuServiceProvider.php
new file mode 100644
index 0000000..eb2605f
--- /dev/null
+++ b/src/Providers/MenuServiceProvider.php
@@ -0,0 +1,104 @@
+ \Tripteki\Menu\Repositories\Eloquent\MenuRepository::class,
+ \Tripteki\Menu\Contracts\Repository\Admin\IMenuAdminRepository::class => \Tripteki\Menu\Repositories\Eloquent\Admin\MenuAdminRepository::class,
+ ];
+
+ /**
+ * @var bool
+ */
+ public static $runsMigrations = true;
+
+ /**
+ * @return bool
+ */
+ public static function shouldRunMigrations()
+ {
+ return static::$runsMigrations;
+ }
+
+ /**
+ * @return void
+ */
+ public static function ignoreMigrations()
+ {
+ static::$runsMigrations = false;
+ }
+
+ /**
+ * @return void
+ */
+ public function boot()
+ {
+ parent::boot();
+
+ $this->dataEventListener();
+
+ $this->registerPublishers();
+ $this->registerCommands();
+ $this->registerMigrations();
+ }
+
+ /**
+ * @return void
+ */
+ protected function registerCommands()
+ {
+ if (! $this->app->isProduction() && $this->app->runningInConsole()) {
+
+ $this->commands(
+ [
+ InstallCommand::class,
+ ]);
+ }
+ }
+
+ /**
+ * @return void
+ */
+ protected function registerMigrations()
+ {
+ if ($this->app->runningInConsole() && static::shouldRunMigrations()) {
+
+ $this->loadMigrationsFrom(__DIR__."/../../database/migrations");
+ }
+ }
+
+ /**
+ * @return void
+ */
+ protected function registerPublishers()
+ {
+ if (! static::shouldRunMigrations()) {
+
+ $this->publishes(
+ [
+ __DIR__."/../../database/migrations" => database_path("migrations"),
+ ],
+
+ "tripteki-laravelphp-menu-migrations");
+ }
+ }
+
+ /**
+ * @return void
+ */
+ public function dataEventListener()
+ {
+ Menu::observe(UniqueIdObserver::class);
+ }
+};
diff --git a/src/Repositories/Eloquent/Admin/MenuAdminRepository.php b/src/Repositories/Eloquent/Admin/MenuAdminRepository.php
new file mode 100644
index 0000000..f2a95b3
--- /dev/null
+++ b/src/Repositories/Eloquent/Admin/MenuAdminRepository.php
@@ -0,0 +1,169 @@
+ $querystring["limit"] ?? request()->query("limit", 10),
+ "current_page" => $querystring["current_page"] ?? request()->query("current_page", 1),
+ ];
+ extract($querystringed);
+
+ $content = QueryBuilder::for(Menu::class)->
+ withTrashed()->
+ defaultSort("nth")->
+ allowedSorts([ "platform", "route", "nth", "title", ])->
+ allowedFilters([ "platform", "route", "nth", "title", ])->
+ paginate($limit, [ "*", ], "current_page", $current_page)->appends(empty($querystring) ? request()->query() : $querystringed);
+
+ return $content;
+ }
+
+ /**
+ * @param int|string $identifier
+ * @param array $querystring|[]
+ * @return mixed
+ */
+ public function get($identifier, $querystring = [])
+ {
+ $content = Menu::findOrFail($identifier);
+
+ return $content;
+ }
+
+ /**
+ * @param int|string $identifier
+ * @param array $data
+ * @return mixed
+ */
+ public function update($identifier, $data)
+ {
+ $content = Menu::findOrFail($identifier);
+
+ DB::beginTransaction();
+
+ try {
+
+ $content->update($data);
+
+ DB::commit();
+
+ } catch (Exception $exception) {
+
+ DB::rollback();
+ }
+
+ return $content;
+ }
+
+ /**
+ * @param array $data
+ * @return mixed
+ */
+ public function create($data)
+ {
+ $content = null;
+
+ DB::beginTransaction();
+
+ try {
+
+ $content = Menu::create($data);
+
+ DB::commit();
+
+ } catch (Exception $exception) {
+
+ DB::rollback();
+ }
+
+ return $content;
+ }
+
+ /**
+ * @param int|string $identifier
+ * @return mixed
+ */
+ public function delete($identifier)
+ {
+ $content = Menu::findOrFail($identifier);
+
+ DB::beginTransaction();
+
+ try {
+
+ $content->forceDelete();
+
+ DB::commit();
+
+ } catch (Exception $exception) {
+
+ DB::rollback();
+ }
+
+ return $content;
+ }
+
+ /**
+ * @param int|string $identifier
+ * @return mixed
+ */
+ public function activate($identifier)
+ {
+ $content = Menu::withTrashed()->findOrFail($identifier);
+
+ DB::beginTransaction();
+
+ try {
+
+ $content->activate();
+
+ DB::commit();
+
+ } catch (Exception $exception) {
+
+ DB::rollback();
+ }
+
+ return $content;
+ }
+
+ /**
+ * @param int|string $identifier
+ * @return mixed
+ */
+ public function deactivate($identifier)
+ {
+ $content = Menu::findOrFail($identifier);
+
+ DB::beginTransaction();
+
+ try {
+
+ $content->deactivate();
+
+ DB::commit();
+
+ } catch (Exception $exception) {
+
+ DB::rollback();
+ }
+
+ return $content;
+ }
+};
diff --git a/src/Repositories/Eloquent/MenuRepository.php b/src/Repositories/Eloquent/MenuRepository.php
new file mode 100644
index 0000000..e39c549
--- /dev/null
+++ b/src/Repositories/Eloquent/MenuRepository.php
@@ -0,0 +1,46 @@
+
+ where("platform", $platform)->
+ where("route", $route)->
+ defaultSort("nth")->
+ allowedSorts([ "platform", "route", "nth", "title", ])->
+ allowedFilters([ "platform", "route", "nth", "title", ])->
+ get();
+
+ return $content;
+ }
+
+ /**
+ * @param string $platform
+ * @param string $route
+ * @param string $id
+ * @param array $querystring|[]
+ * @return mixed
+ */
+ public function get($platform, $route, $id, $querystring = [])
+ {
+ $content = Menu::where("platform", $platform)->where("route", $route)->findOrFail($id);
+
+ return $content;
+ }
+};
diff --git a/src/Repositories/QueryBuilder/.gitkeep b/src/Repositories/QueryBuilder/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/stubs/app/Exports/Menus/MenuExport.php b/stubs/app/Exports/Menus/MenuExport.php
new file mode 100644
index 0000000..9a053c2
--- /dev/null
+++ b/stubs/app/Exports/Menus/MenuExport.php
@@ -0,0 +1,57 @@
+ [ "font" => [ "bold" => true, ], ],
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ public function headings(): array
+ {
+ return [
+
+ "Platform",
+ "Route",
+ "Position",
+ "Title",
+ "Icon",
+ "Description",
+ ];
+ }
+
+ /**
+ * @return \Illuminate\Database\Eloquent\Collection
+ */
+ public function collection()
+ {
+ return Menu::all([
+
+ "platform",
+ "route",
+ "nth",
+ "title",
+ "icon",
+ "description",
+ ]);
+ }
+};
diff --git a/stubs/app/Http/Controllers/Admin/Menu/MenuAdminController.php b/stubs/app/Http/Controllers/Admin/Menu/MenuAdminController.php
new file mode 100644
index 0000000..3a218bd
--- /dev/null
+++ b/stubs/app/Http/Controllers/Admin/Menu/MenuAdminController.php
@@ -0,0 +1,416 @@
+menuAdminRepository = $menuAdminRepository;
+ }
+
+ /**
+ * @OA\Get(
+ * path="/admin/menus",
+ * tags={"Admin Menu"},
+ * summary="Index",
+ * @OA\Parameter(
+ * required=false,
+ * in="query",
+ * name="limit",
+ * description="Menu's Pagination Limit."
+ * ),
+ * @OA\Parameter(
+ * required=false,
+ * in="query",
+ * name="current_page",
+ * description="Menu's Pagination Current Page."
+ * ),
+ * @OA\Parameter(
+ * required=false,
+ * in="query",
+ * name="order",
+ * description="Menu's Pagination Order."
+ * ),
+ * @OA\Parameter(
+ * required=false,
+ * in="query",
+ * name="filter[]",
+ * description="Menu's Pagination Filter."
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * )
+ * )
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function index(Request $request)
+ {
+ $data = [];
+ $statecode = 200;
+
+ $data = $this->menuAdminRepository->all();
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Get(
+ * path="/admin/menus/{identifier}",
+ * tags={"Admin Menu"},
+ * summary="Show",
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="identifier",
+ * description="Menu's Identifier."
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="Not Found."
+ * )
+ * )
+ *
+ * @param \App\Http\Requests\Admin\Menus\MenuShowValidation $request
+ * @param string $identifier
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function show(MenuShowValidation $request, $identifier)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 200;
+
+ $data = $this->menuAdminRepository->get($identifier);
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Post(
+ * path="/admin/menus",
+ * tags={"Admin Menu"},
+ * summary="Store",
+ * @OA\RequestBody(
+ * @OA\MediaType(
+ * mediaType="application/x-www-form-urlencoded",
+ * @OA\Schema(
+ * @OA\Property(
+ * property="platform",
+ * type="string",
+ * description="Menu's Platform."
+ * ),
+ * @OA\Property(
+ * property="route",
+ * type="string",
+ * description="Menu's Route."
+ * ),
+ * @OA\Property(
+ * property="nth",
+ * type="integer",
+ * description="Menu's Position."
+ * ),
+ * @OA\Property(
+ * property="title",
+ * type="string",
+ * description="Menu's Title."
+ * ),
+ * @OA\Property(
+ * property="icon",
+ * type="string",
+ * description="Menu's Icon."
+ * ),
+ * @OA\Property(
+ * property="description",
+ * type="string",
+ * description="Menu's Description."
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(
+ * response=201,
+ * description="Created."
+ * ),
+ * @OA\Response(
+ * response=422,
+ * description="Unprocessable Entity."
+ * )
+ * )
+ *
+ * @param \App\Http\Requests\Admin\Menus\MenuStoreValidation $request
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function store(MenuStoreValidation $request)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 202;
+
+ $data = $this->menuAdminRepository->create($form);
+
+ if ($data) {
+
+ $statecode = 201;
+ }
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Put(
+ * path="/admin/menus/{identifier}",
+ * tags={"Admin Menu"},
+ * summary="Update",
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="identifier",
+ * description="Menu's Identifier."
+ * ),
+ * @OA\RequestBody(
+ * @OA\MediaType(
+ * mediaType="application/x-www-form-urlencoded",
+ * @OA\Schema(
+ * @OA\Property(
+ * property="platform",
+ * type="string",
+ * description="Menu's Platform."
+ * ),
+ * @OA\Property(
+ * property="route",
+ * type="string",
+ * description="Menu's Route."
+ * ),
+ * @OA\Property(
+ * property="nth",
+ * type="integer",
+ * description="Menu's Position."
+ * ),
+ * @OA\Property(
+ * property="title",
+ * type="string",
+ * description="Menu's Title."
+ * ),
+ * @OA\Property(
+ * property="icon",
+ * type="string",
+ * description="Menu's Icon."
+ * ),
+ * @OA\Property(
+ * property="description",
+ * type="string",
+ * description="Menu's Description."
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(
+ * response=201,
+ * description="Created."
+ * ),
+ * @OA\Response(
+ * response=422,
+ * description="Unprocessable Entity."
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="Not Found."
+ * )
+ * )
+ *
+ * @param \App\Http\Requests\Admin\Menus\MenuUpdateValidation $request
+ * @param string $identifier
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function update(MenuUpdateValidation $request, $identifier)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 202;
+
+ $data = $this->menuAdminRepository->update($identifier, $form);
+
+ if ($data) {
+
+ $statecode = 201;
+ }
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Delete(
+ * path="/admin/menus/{identifier}",
+ * tags={"Admin Menu"},
+ * summary="Destroy",
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="identifier",
+ * description="Menu's Identifier."
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * ),
+ * @OA\Response(
+ * response=422,
+ * description="Unprocessable Entity."
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="Not Found."
+ * )
+ * )
+ *
+ * @param \App\Http\Requests\Admin\Menus\MenuDestroyValidation $request
+ * @param string $identifier
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function destroy(MenuDestroyValidation $request, $identifier)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 202;
+
+ $data = $this->menuAdminRepository->delete($identifier);
+
+ if ($data) {
+
+ $statecode = 200;
+ }
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Post(
+ * path="/admin/menus-import",
+ * tags={"Admin Menu"},
+ * summary="Import",
+ * @OA\RequestBody(
+ * @OA\MediaType(
+ * mediaType="multipart/form-data",
+ * @OA\Schema(
+ * @OA\Property(
+ * property="file",
+ * type="file",
+ * description="Menu's File."
+ * )
+ * )
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * ),
+ * @OA\Response(
+ * response=422,
+ * description="Unprocessable Entity."
+ * )
+ * )
+ *
+ * @param \Tripteki\Helpers\Http\Requests\FileImportValidation $request
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function import(FileImportValidation $request)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 200;
+
+ if ($form["file"]->getClientOriginalExtension() == "csv" || $form["file"]->getClientOriginalExtension() == "txt") {
+
+ $data = Excel::import(new MenuImport(), $form["file"], null, \Maatwebsite\Excel\Excel::CSV);
+
+ } else if ($form["file"]->getClientOriginalExtension() == "xls") {
+
+ $data = Excel::import(new MenuImport(), $form["file"], null, \Maatwebsite\Excel\Excel::XLS);
+
+ } else if ($form["file"]->getClientOriginalExtension() == "xlsx") {
+
+ $data = Excel::import(new MenuImport(), $form["file"], null, \Maatwebsite\Excel\Excel::XLSX);
+ }
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Get(
+ * path="/admin/menus-export",
+ * tags={"Admin Menu"},
+ * summary="Export",
+ * @OA\Parameter(
+ * required=false,
+ * in="query",
+ * name="file",
+ * schema={"type": "string", "enum": {"csv", "xls", "xlsx"}},
+ * description="Menu's File."
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * ),
+ * @OA\Response(
+ * response=422,
+ * description="Unprocessable Entity."
+ * )
+ * )
+ *
+ * @param \Tripteki\Helpers\Http\Requests\FileExportValidation $request
+ * @return mixed
+ */
+ public function export(FileExportValidation $request)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 200;
+
+ if ($form["file"] == "csv") {
+
+ $data = Excel::download(new MenuExport(), "Menu.csv", \Maatwebsite\Excel\Excel::CSV);
+
+ } else if ($form["file"] == "xls") {
+
+ $data = Excel::download(new MenuExport(), "Menu.xls", \Maatwebsite\Excel\Excel::XLS);
+
+ } else if ($form["file"] == "xlsx") {
+
+ $data = Excel::download(new MenuExport(), "Menu.xlsx", \Maatwebsite\Excel\Excel::XLSX);
+ }
+
+ return $data;
+ }
+};
diff --git a/stubs/app/Http/Controllers/Menu/MenuController.php b/stubs/app/Http/Controllers/Menu/MenuController.php
new file mode 100644
index 0000000..b967391
--- /dev/null
+++ b/stubs/app/Http/Controllers/Menu/MenuController.php
@@ -0,0 +1,119 @@
+menuRepository = $menuRepository;
+ }
+
+ /**
+ * @OA\Get(
+ * path="/menus/{platform}/routes/{route}",
+ * tags={"Menus"},
+ * summary="Index",
+ * security={{ "bearerAuth": {} }},
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="platform",
+ * description="Menu's Platform."
+ * ),
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="route",
+ * description="Menu's Route."
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * )
+ * )
+ *
+ * @param \App\Http\Requests\Menus\MenuIndexValidation $request
+ * @param string $platform
+ * @param string $route
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function index(MenuIndexValidation $request, $platform, $route)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 200;
+
+ $data = $this->menuRepository->all($platform, $route);
+
+ return iresponse($data, $statecode);
+ }
+
+ /**
+ * @OA\Get(
+ * path="/menus/{platform}/routes/{route}/ids/{id}",
+ * tags={"Menus"},
+ * summary="Show",
+ * security={{ "bearerAuth": {} }},
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="platform",
+ * description="Menu's Platform."
+ * ),
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="route",
+ * description="Menu's Route."
+ * ),
+ * @OA\Parameter(
+ * required=true,
+ * in="path",
+ * name="id",
+ * description="Menu's Id."
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Success."
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="Not Found."
+ * )
+ * )
+ *
+ * @param \App\Http\Requests\Menus\MenuShowValidation $request
+ * @param string $platform
+ * @param string $route
+ * @param string $id
+ * @return \Illuminate\Http\JsonResponse
+ */
+ public function show(MenuShowValidation $request, $platform, $route, $id)
+ {
+ $form = $request->validated();
+ $data = [];
+ $statecode = 200;
+
+ $data = $this->menuRepository->get($platform, $route, $id);
+
+ return iresponse($data, $statecode);
+ }
+};
diff --git a/stubs/app/Http/Requests/Admin/Menus/MenuDestroyValidation.php b/stubs/app/Http/Requests/Admin/Menus/MenuDestroyValidation.php
new file mode 100644
index 0000000..997867b
--- /dev/null
+++ b/stubs/app/Http/Requests/Admin/Menus/MenuDestroyValidation.php
@@ -0,0 +1,39 @@
+ $this->route("id"),
+ ];
+ }
+
+ /**
+ * @return bool
+ */
+ public function authorize()
+ {
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function rules()
+ {
+ return [
+
+ "id" => "required|string|exists:".Menu::class,
+ ];
+ }
+};
diff --git a/stubs/app/Http/Requests/Admin/Menus/MenuShowValidation.php b/stubs/app/Http/Requests/Admin/Menus/MenuShowValidation.php
new file mode 100644
index 0000000..87b38a8
--- /dev/null
+++ b/stubs/app/Http/Requests/Admin/Menus/MenuShowValidation.php
@@ -0,0 +1,39 @@
+ $this->route("id"),
+ ];
+ }
+
+ /**
+ * @return bool
+ */
+ public function authorize()
+ {
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function rules()
+ {
+ return [
+
+ "id" => "required|string|exists:".Menu::class,
+ ];
+ }
+};
diff --git a/stubs/app/Http/Requests/Admin/Menus/MenuStoreValidation.php b/stubs/app/Http/Requests/Admin/Menus/MenuStoreValidation.php
new file mode 100644
index 0000000..542bfeb
--- /dev/null
+++ b/stubs/app/Http/Requests/Admin/Menus/MenuStoreValidation.php
@@ -0,0 +1,45 @@
+
+ */
+ public function rules()
+ {
+ return [
+
+ "platform" => "required|string|max:8|lowercase",
+ "route" => "required|string|max:127|regex:/[0-9a-zA-Z_-\\\/]+/",
+ "nth" => "required|integer",
+ "title" => [
+
+ "required",
+ "string",
+ "lowercase",
+ "max:32",
+ "alpha_dash:ascii",
+ Rule::unique(Menu::class)->where(function ($query) {
+
+ return $query->where("platform", $this->input("platform"))->where("route", $this->input("route"));
+ }),
+ ],
+ "icon" => "present|string|max:255|nullable",
+ "description" => "present|string|max:255|nullable",
+ ];
+ }
+};
diff --git a/stubs/app/Http/Requests/Admin/Menus/MenuUpdateValidation.php b/stubs/app/Http/Requests/Admin/Menus/MenuUpdateValidation.php
new file mode 100644
index 0000000..0ecf718
--- /dev/null
+++ b/stubs/app/Http/Requests/Admin/Menus/MenuUpdateValidation.php
@@ -0,0 +1,57 @@
+ $this->route("id"),
+ ];
+ }
+
+ /**
+ * @return bool
+ */
+ public function authorize()
+ {
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function rules()
+ {
+ return [
+
+ "id" => "required|string|exists:".Menu::class,
+ "platform" => "required|string|max:8|lowercase",
+ "route" => "required|string|max:127|regex:/[0-9a-zA-Z_-\\\/]+/",
+ "nth" => "required|integer",
+ "title" => [
+
+ "required",
+ "string",
+ "lowercase",
+ "max:32",
+ "alpha_dash:ascii",
+ Rule::unique(Menu::class)->where(function ($query) {
+
+ return $query->where("platform", $this->input("platform"))->where("route", $this->input("route"));
+ }),
+ ],
+ "icon" => "present|string|max:255|nullable",
+ "description" => "present|string|max:255|nullable",
+ ];
+ }
+};
diff --git a/stubs/app/Http/Requests/Menus/MenuIndexValidation.php b/stubs/app/Http/Requests/Menus/MenuIndexValidation.php
new file mode 100644
index 0000000..eb9d9e4
--- /dev/null
+++ b/stubs/app/Http/Requests/Menus/MenuIndexValidation.php
@@ -0,0 +1,40 @@
+ $this->route("platform"),
+ "route" => $this->route("route"),
+ ];
+ }
+
+ /**
+ * @return bool
+ */
+ public function authorize()
+ {
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function rules()
+ {
+ return [
+
+ "platform" => "required|string",
+ "route" => "required|string",
+ ];
+ }
+};
diff --git a/stubs/app/Http/Requests/Menus/MenuShowValidation.php b/stubs/app/Http/Requests/Menus/MenuShowValidation.php
new file mode 100644
index 0000000..d06cde9
--- /dev/null
+++ b/stubs/app/Http/Requests/Menus/MenuShowValidation.php
@@ -0,0 +1,47 @@
+ $this->route("platform"),
+ "route" => $this->route("route"),
+ "id" => $this->route("id"),
+ ];
+ }
+
+ /**
+ * @return bool
+ */
+ public function authorize()
+ {
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function rules()
+ {
+ return [
+
+ "platform" => "required|string",
+ "route" => "required|string",
+ "id" => Rule::exists(Menu::class)->where(function ($query) {
+
+ return $query->where("platform", $this->input("platform"))->where("route", $this->input("route"));
+ }),
+ ];
+ }
+};
diff --git a/stubs/app/Http/Responses/.gitkeep b/stubs/app/Http/Responses/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/stubs/app/Imports/Menus/MenuImport.php b/stubs/app/Imports/Menus/MenuImport.php
new file mode 100644
index 0000000..22327de
--- /dev/null
+++ b/stubs/app/Imports/Menus/MenuImport.php
@@ -0,0 +1,81 @@
+rules();
+
+ $rows->map(function ($row) use ($validator) {
+
+ Validator::make($rows->toArray(), [
+
+ "*.0" => $validator["platform"],
+ "*.1" => $validator["route"],
+ "*.2" => $validator["nth"],
+ "*.3" => [
+
+ "required",
+ "string",
+ "lowercase",
+ "max:32",
+ "alpha_dash:ascii",
+ Rule::unique(Menu::class, "title")->where(function ($query) use ($row) {
+
+ return $query->where("platform", $row[0])->where("route", $row[1]);
+ }),
+ ],
+ "*.4" => $validator["icon"],
+ "*.5" => $validator["description"],
+
+ ])->validate();
+ });
+ }
+
+ /**
+ * @param \Illuminate\Support\Collection $rows
+ * @return void
+ */
+ public function collection(Collection $rows)
+ {
+ $this->validate($rows);
+
+ $menuAdminRepository = app(IMenuAdminRepository::class);
+
+ foreach ($rows as $row) {
+
+ $menuAdminRepository->create([
+
+ "platform" => $row[0],
+ "route" => $row[1],
+ "nth" => $row[2],
+ "title" => $row[3],
+ "icon" => $row[4],
+ "description" => $row[5],
+ ]);
+ }
+ }
+};
diff --git a/stubs/routes/admin/menu.php b/stubs/routes/admin/menu.php
new file mode 100644
index 0000000..823e30b
--- /dev/null
+++ b/stubs/routes/admin/menu.php
@@ -0,0 +1,14 @@
+middleware(config("adminer.middleware.admin"))->group(function () {
+
+ /**
+ * Menus.
+ */
+ Route::apiResource("menus", MenuAdminController::class)->parameters([ "menus" => "menu", ]);
+ Route::get("menus-import", [ MenuAdminController::class, "export", ]);
+ Route::get("menus-export", [ MenuAdminController::class, "export", ]);
+});
diff --git a/stubs/routes/user/menu.php b/stubs/routes/user/menu.php
new file mode 100644
index 0000000..3b622cd
--- /dev/null
+++ b/stubs/routes/user/menu.php
@@ -0,0 +1,12 @@
+middleware(config("adminer.middleware.user"))->group(function () {
+
+ /**
+ * Menus.
+ */
+ Route::apiResource("menus.routes.ids", MenuController::class)->only([ "index", "show", ])->parameters([ "menus" => "menu", ]);
+});