Menú Lateral Recursivo & RBAC
El menú de navegación lateral (Sidebar) de Mañuti está construido como un componente Blade modular y recursivo (App\View\Components\Backend\Sidebar), capaz de renderizar árboles jerárquicos de profundidad ilimitada con filtrado automático de permisos por capacidades de negocio.
1. Arquitectura de Separación de Responsabilidades
El menú sigue una estricta división en tres niveles:
- Clase de Componente (
Sidebar.php): Administra la estructura de datos, evalúa permisos y determina las rutas activas. - Vista Contenedora (
sidebar.blade.php): Renderiza el marco estructural, logotipo y scrollbar. - Componente Recursivo (
sidebar-item.blade.php): Se invoca a sí mismo para pintar submenús, flechas y enlaces de forma infinita.
flowchart TD
BASE["[base.blade.php]"]
SIDEBAR_COMP["[<x-backend.sidebar />]"]
SIDEBAR_CLASS["Instancia Sidebar.php (defineMenu())"]
SIDEBAR_VIEW["[sidebar.blade.php]"]
ITEM_COMP["[<x-backend.sidebar-item />] (Nivel 1)"]
HAS_SUBMENU{"¿Posee 'submenu'?"}
LINK["[Renderiza <a>]"]
ACCORDION["[Renderiza Acordeón]"]
BASE --> SIDEBAR_COMP
SIDEBAR_COMP --> SIDEBAR_CLASS
SIDEBAR_CLASS --> SIDEBAR_VIEW
SIDEBAR_VIEW -->|"(Bucle de Nivel 1)"| ITEM_COMP
ITEM_COMP --> HAS_SUBMENU
HAS_SUBMENU -->|"No"| LINK
HAS_SUBMENU -->|"Sí"| ACCORDION
ACCORDION -->|"(Auto-invocación recursiva)"| ITEM_COMP
2. Definición Estructurada del Menú (Sidebar.php)
// app/View/Components/Backend/Sidebar.php
namespace App\View\Components\Backend;
use Illuminate\View\Component;
class Sidebar extends Component
{
public function defineMenu(): array
{
return [
[
'type' => 'heading',
'title' => 'ADMINISTRACIÓN',
],
[
'title' => 'Gestión de Acceso',
'icon' => 'ki-outline ki-shield-tick',
'active_prefixes' => ['admin.users', 'admin.roles', 'admin.permissions'],
'any_permission' => ['users.view', 'roles.view', 'permissions.view'],
'submenu' => [
[
'title' => 'Usuarios',
'route' => 'admin.users.index',
'permission' => 'users.view',
],
[
'title' => 'Roles de Sistema',
'route' => 'admin.roles.index',
'permission' => 'roles.view',
],
[
'title' => 'Permisos Atómicos',
'route' => 'admin.permissions.index',
'permission' => 'permissions.view',
],
],
],
];
}
}
3. Filtrado por Permisos en Cascada
permission: Exige una capacidad atómica exacta para mostrar el enlace final.any_permission: Si el usuario posee al menos uno de los permisos listados, el nodo padre (carpeta/acordeón) se vuelve visible. Si no posee ninguno, la sección completa se excluye del HTML, evitando carpetas vacías.active_prefixes: Mantiene el acordeón abierto si la ruta actual coincide con los prefijos configurados.