| Current Path : /var/www/html/redd/docs/ |
| Current File : /var/www/html/redd/docs/ROUTE-MANAGEMENT.md |
# Route Management Module
Module untuk auto-generate dan manage application routes, inspired by Yii2's mdm/mimin RBAC route system.
## Overview
Module ini membolehkan admin scan semua registered routes dari Laravel, generate ke database, dan gunakannya sebagai menu link resources.
## Structure
```
app/
├── Models/Backend/
│ └── Route.php # Eloquent model
├── Services/
│ ├── RouteScanner.php # Scan registered routes
│ └── ControllerScanner.php # Scan controller methods
└── Http/Controllers/Backend/
└── RouteController.php # CRUD + generate/sync
database/migrations/
└── 2026_05_17_000001_create_routes_table.php
resources/views/backend/module/routes/
├── index.blade.php # List routes
├── create.blade.php # Add route
├── edit.blade.php # Edit route
└── available.blade.php # Compare registered vs available
```
## Database Schema
### routes table
| Column | Type | Description |
|-------------|---------------|--------------------------------|
| id | bigint | Primary key |
| name | varchar(255) | Route name (e.g. `ref.index`) |
| uri | varchar(255) | URI path (e.g. `/admin/ref`) |
| method | varchar(50) | HTTP method (GET, POST, etc) |
| controller | varchar(255) | Full controller class name |
| action | varchar(255) | Method name in controller |
| middleware | varchar(255) | Middleware stack |
| type | varchar(20) | web / api / admin |
| status | boolean | Active/Inactive |
| alias | varchar(255) | Display alias |
| created_at | timestamp | |
| updated_at | timestamp | |
| deleted_at | timestamp | Soft deletes |
## Models
### Route Model (`app/Models/Backend/Route.php`)
**Attributes (Fillable):**
- `name` - Route name (nullable)
- `uri` - URI path
- `method` - HTTP method
- `controller` - Controller class
- `action` - Action method
- `middleware` - Middleware
- `type` - web/api/admin
- `status` - boolean
- `alias` - Display name
**Static Methods:**
- `Route::rules($id)` - Validation rules
- `Route::methodColors()` - Tailadmin badge colors for HTTP methods
- `Route::typeColors()` - Badge colors for route types
**Scopes:**
- `Route::web()` - Filter web routes
- `Route::api()` - Filter api routes
- `Route::admin()` - Filter admin routes
- `Route::active()` - Filter active routes
- `Route::inactive()` - Filter inactive routes
## Services
### RouteScanner (`app/Services/RouteScanner.php`)
Scan semua registered routes dari `Route::getRoutes()`.
**Methods:**
- `scan()` - Return array semua routes
- `scanAndCache()` - Scan + cache untuk 1 hari
- `getCached()` - Get dari cache
- `clearCache()` - Clear cache
- `refresh()` - Clear + rescan
**Extracted Data:**
```php
[
'name' => 'route.name',
'uri' => '/admin/users',
'method' => 'GET',
'controller' => 'App\\Http\\Controllers\\Backend\\UserController',
'action' => 'index',
'middleware' => 'auth,admin',
'type' => 'admin',
]
```
**Filters (skipped):**
- Closure routes
- Debug routes (`_debugbar`, `telescope`, `horizon`)
- Vendor routes
- Sanctum/Passport routes
### ControllerScanner (`app/Services/ControllerScanner.php`)
Scan semua controllers dalam `app/Http/Controllers/`.
**Methods:**
- `scan()` - Recursively scan controllers
- `scanAndCache()` - Scan + cache
- `getCached()` - Get from cache
- `clearCache()` - Clear cache
**Logic:**
1. Find semua file `*Controller.php`
2. Use ReflectionClass untuk get public methods
3. Skip constructor, middleware, magic methods
4. Generate URI dari controller name + method (kebab-case)
5. Auto-detect resource methods (index, create, store, show, edit, update, destroy)
## RouteController (`app/Http/Controllers/Backend/RouteController.php`)
### Methods
| Method | Route | Description |
|--------|-------|-------------|
| `index()` | GET /admin/routes | List all routes with search/filter |
| `create()` | GET /admin/routes/create | Show create form |
| `store()` | POST /admin/routes | Save new route |
| `edit($id)` | GET /admin/routes/{id}/edit | Show edit form |
| `update($request, $id)` | PUT /admin/routes/{id} | Update route |
| `destroy($id)` | DELETE /admin/routes/{id} | Delete route |
| `generate($request)` | POST /admin/routes/generate | Scan & create/update routes |
| `sync()` | GET /admin/routes/sync | Sync all routes |
| `refresh()` | GET /admin/routes/refresh | Clear cache & rescan |
| `available()` | GET /admin/routes/available | Show unregistered routes |
| `bulkDelete()` | POST /admin/routes/bulk-delete | Delete multiple routes |
| `bulkStatus()` | POST /admin/routes/bulk-status/{status} | Activate/deactivate multiple |
### Query Parameters (index)
- `search` - Search name, uri, controller, action
- `type` - Filter web/api/admin
- `method` - Filter GET/POST/PUT/PATCH/DELETE
- `status` - Filter active/inactive
## Views
### index.blade.php
Table columns:
- **No** - Row number
- **Route Name** - name field (nullable)
- **URL** - URI + full URL link
- **Method** - HTTP method badge (color coded)
- **Controller** - Controller class + action
- **Type** - web/api/admin badge (color coded)
- **Status** - Active/Inactive badge
- **Actions** - Edit/Delete buttons
Features:
- Search & filter forms
- Generate Routes button (green)
- Sync All button
- Refresh Cache button
- Available Routes button
- Pagination (20 per page)
- Delete confirmation (SweetAlert)
### create.blade.php / edit.blade.php
Form fields:
- URI (text)
- Route Name (text)
- HTTP Method (dropdown)
- Type (dropdown: web/api/admin)
- Status (dropdown: Active/Inactive)
- Controller (text)
- Action (text)
- Middleware (text)
- Alias (text)
### available.blade.php
Two columns comparison:
- **Not Yet Registered** - Routes scanned but not in DB (red theme)
- **Already Registered** - Routes in DB (green theme)
Generate button to add missing routes.
## Usage Flow
### 1. Generate Routes (First Time)
```
Admin Panel > Routes > Click "Generate Routes"
```
System will:
1. Scan all registered routes from `Route::getRoutes()`
2. Scan all controller methods
3. Insert new routes to database
4. Update existing routes if changed
5. Show success message with count
### 2. Manage Routes
- **Add Manually** - Click "Add Route" button
- **Edit** - Click edit icon on row
- **Delete** - Click delete icon (with confirmation)
- **Bulk Delete** - Select checkboxes > Delete Selected
- **Bulk Activate/Deactivate** - Select > click activate/deactivate buttons
### 3. Use in Menu
In Backend Menu / Frontend Menu management:
1. Create new menu item
2. Set `menu_link` to route name (e.g. `admin.routes.index`)
3. Or set to full URI (e.g. `/admin/routes`)
4. Set `menu_active_route` for active state detection
### 4. Sync Routes (Regularly)
Click "Sync All" to:
1. Scan for new routes
2. Add missing routes to DB
3. Remove stale routes (routes starting with `generated_` that no longer exist)
## Permissions
Required permissions for routes module:
- `route.view` - View routes list
- `route.create` - Create/Generate routes
- `route.update` - Edit routes
- `route.delete` - Delete routes
These permissions are added in `BackendMenuSeeder`.
## Route Type Detection
Type is auto-detected based on:
- URI prefix (`api/`, `admin/`)
- Middleware (`api`, `admin`)
Default: `web`
## HTTP Method Badge Colors
| Method | Color | Tailadmin Class |
|--------|-------|-----------------|
| GET | Brand | `bg-brand-50 text-brand-600` |
| POST | Success (Green) | `bg-success-50 text-success-600` |
| PUT | Warning (Yellow) | `bg-warning-50 text-warning-600` |
| PATCH | Warning (Yellow) | `bg-warning-50 text-warning-600` |
| DELETE | Error (Red) | `bg-error-50 text-error-600` |
| OPTIONS | Gray | `bg-gray-50 text-gray-600` |
| HEAD | Brand | `bg-brand-50 text-brand-600` |
## Route Type Badge Colors
| Type | Color | Tailadmin Class |
|------|-------|-----------------|
| web | Brand | `bg-brand-50 text-brand-600` |
| api | Purple | `bg-purple-50 text-purple-600` |
| admin | Pink | `bg-pink-50 text-pink-600` |
## Caching
Services use Laravel cache:
- Key: `scanned_routes` (RouteScanner)
- Key: `scanned_controllers` (ControllerScanner)
- TTL: 1 day
Clear cache via:
- "Refresh Cache" button
- `RouteScanner::clearCache()`
- `ControllerScanner::clearCache()`
## Notes
- Routes with `name` can be used with `route()` helper
- Routes without `name` use URI directly
- Soft deletes enabled - deleted routes can be restored
- Method column accepts comma-separated for multiple methods (e.g. `GET,POST`)
- URI uses `/` prefix convention
## Usage Examples
### 1. Get All Active Routes
```php
use App\Models\Backend\Route;
$routes = Route::active()->get();
foreach ($routes as $route) {
echo $route->name . ' -> ' . $route->uri;
}
```
### 2. Get Routes by Type
```php
// Admin routes only
$adminRoutes = Route::active()->admin()->get();
// Web routes only
$webRoutes = Route::active()->web()->get();
// API routes only
$apiRoutes = Route::active()->api()->get();
```
### 3. Get Routes by HTTP Method
```php
$getRoutes = Route::active()->where('method', 'GET')->get();
$postRoutes = Route::active()->where('method', 'POST')->get();
```
### 4. Search Routes
```php
// In controller
$routes = Route::where('name', 'like', '%ref%')
->orWhere('uri', 'like', '%ref%')
->active()
->get();
```
### 5. Use in Menu Link Selection
```php
// Get all active routes for dropdown
$routeOptions = Route::active()
->orderBy('uri')
->pluck('name', 'uri')
->toArray();
// Or with route name as key
$routeOptions = Route::active()
->whereNotNull('name')
->pluck('name', 'name')
->toArray();
```
### 6. Check if Route Exists
```php
use App\Models\Backend\Route;
$exists = Route::where('uri', '/admin/ref')->exists();
if ($exists) {
echo "Route exists";
}
```
### 7. Get Single Route
```php
$route = Route::where('name', 'ref.index')->first();
if ($route) {
echo $route->uri; // /admin/ref
echo route($route->name); // Full URL
}
```
### 8. Use Route Name for route() Helper
In views or controllers:
```php
// If route has name stored
{{ route('ref.index') }}
// If using URI directly
{{ url('/admin/ref') }}
```
### 9. Generate Route Link in Menu
```php
// In your menu rendering logic
$route = Route::where('menu_link', $menuItem->menu_link)->first();
if ($route) {
$link = $route->name ? route($route->name) : url($route->uri);
} else {
$link = url($menuItem->menu_link);
}
```
### 10. Bulk Update Route Status
```php
// Deactivate all admin routes
Route::where('type', 'admin')->update(['status' => false]);
// Activate specific routes
$routeIds = [1, 2, 3];
Route::whereIn('id', $routeIds)->update(['status' => true]);
```
## Where It's Used
### 1. BackendMenuSeeder
Routes are registered as menu items:
```php
$this->menu('Routes', 'admin.routes.index', null, ['route.view', 'route.create', 'route.update', 'route.delete'], $backend->menu_id);
```
Permissions added:
- `route.view`
- `route.create`
- `route.update`
- `route.delete`
### 2. Menu Link Selection
In Backend Menu / Frontend Menu management forms, routes can be selected as `menu_link` values:
```php
// In your menu form view
<select name="menu_link">
<option value="">-- Select Route --</option>
@foreach(\App\Models\Backend\Route::active()->get() as $route)
<option value="{{ $route->name ?? $route->uri }}">
{{ $route->name ?? $route->uri }} ({{ $route->method }})
</option>
@endforeach
</select>
```
### 3. Active Route Detection
In layouts or menu partials:
```php
@php
use App\Models\Backend\Route;
$activeRoutes = Route::active()
->where('menu_active_route', 'like', '%' . Request::route()->getName() . '%')
->first();
@endphp
@if($activeRoutes)
<li class="mm-active">...</li>
@endif
```
### 4. Permission Generation
In AutoPermissionController or similar:
```php
// Generate permissions from routes
foreach (Route::active()->get() as $route) {
$permission = $route->name;
if ($permission) {
Permission::findOrCreate($permission, 'admin');
}
}
```
### 5. Route Resource for Menu
```php
// Example: Create menu link for content-photo-list
$route = Route::where('name', 'content-photo-list.index')->first();
// Result:
// name: content-photo-list.index
// uri: /admin/content-photo-list
// method: GET
// type: admin
// controller: App\Http\Controllers\Backend\ContentPhotoListController
// action: index
```
### 6. API Response for Frontend
```php
// Return routes as JSON for frontend
Route::active()
->select('name', 'uri', 'method', 'type')
->orderBy('uri')
->get();
// Output:
[
{"name":"ref.index","uri":"/admin/ref","method":"GET","type":"admin"},
{"name":"ref.create","uri":"/admin/ref/create","method":"GET","type":"admin"},
...
]
```
## Integration with Other Modules
### 1. BackendMenu (menu link storage)
The `menu_link` field stores route names:
```php
$menu->menu_link = 'content-photo-list.index';
$menu->menu_active_route = ['content-photo-list.index', 'content-photo-list.create'];
```
### 2. RolePermission (permission assignment)
Permissions derived from route names:
```php
// Permission: content-photo-list.index
// Can be assigned to roles via Spatie
$role->givePermissionTo('content-photo-list.index');
```
### 3. Activity Logging
Route model uses SoftDeletes for audit trail.
## Common Issues
### 1. Route Not Found in Menu
Check that:
- Route exists in database (`Route::where('name', 'ref.index')->exists()`)
- Route has `status = true`
- Route name matches exactly (case-sensitive)
### 2. URL Not Generating
```php
$route = Route::where('name', 'ref.index')->first();
if ($route && $route->name) {
echo route($route->name); // Works
} else {
echo url($route->uri); // Fallback
}
```
### 3. Sync Not Finding Routes
Run "Refresh Cache" first:
```php
$scanner = app(\App\Services\RouteScanner::class);
$scanner->refresh();
```
### 4. Method Column Too Short
The `method` column accepts multiple methods (comma-separated). Current max is `VARCHAR(50)`, sufficient for all cases.
### 5. Edit Form Shows Empty / Create Form Instead of Edit Data
**Problem:**
When clicking edit on a route, the form shows empty fields or create form instead of existing data.
**Why This Happens:**
Laravel Route Model Binding conflict. The `Route` model in this module has name conflict with Laravel's built-in `Illuminate\Routing\Route` class.
When using type hint `Route $route` in controller methods:
```php
public function edit(Route $route)
```
Laravel's router tries to resolve the `Route` type hint using its own Route class (which represents URL routes, not the database model), not our `App\Models\Backend\Route` model.
This causes:
1. Form shows empty or create form
2. `$route->id` returns null or wrong value
3. `route('admin.routes.update', ['id' => $route->id])` fails with "Missing required parameter"
**Solution:**
Use explicit ID parameter and find model manually instead of Route Model Binding:
```php
// WRONG - causes conflict
public function edit(Route $route)
{
return view('...', ['route' => $route]);
}
// CORRECT - explicit find
public function edit($id)
{
$route = Route::findOrFail($id);
return view('...', ['route' => $route]);
}
```
**Controller Methods Updated:**
```php
public function edit($id)
{
$route = Route::findOrFail($id);
// ...
}
public function update(Request $request, $id)
{
$route = Route::findOrFail($id);
// ...
}
public function destroy($id)
{
$route = Route::findOrFail($id);
// ...
}
```
**Why Use `url()` Helper Instead of `route()` in Views:**
In edit.blade.php, use `url()` helper instead of `route()` to avoid parameter issues:
```php
// Instead of route() which may have parameter issues
<form action="{{ url('/admin/routes/' . $route->id) }}" method="POST">
// Or use route() with explicit array syntax
<form action="{{ route('admin.routes.update', ['id' => $route->id]) }}" method="POST">
```
### 6. URL Generation Error - Missing Parameter
**Error:**
```
UrlGenerationException: Missing required parameter for [Route: admin.routes.update] [URI: admin/routes/{id}] [Missing parameter: id]
```
**Cause:**
When using `route('admin.routes.update', $route->id)` without explicit key, Laravel may not correctly pass the parameter.
**Fix:**
Always use explicit key in array:
```php
route('admin.routes.update', ['id' => $route->id])
```
Or use `url()` helper:
```php
url('/admin/routes/' . $route->id)
```