gsebastiao / laravel-menu
Menus dinâmicos e hierárquicos (N níveis) para Laravel, com controlo de permissões flexível (none | string | id) e cache. 100% independente de qualquer pacote de permissões.
Requires
- php: ^8.2
- illuminate/cache: ^11.0|^12.0|^13.0
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/routing: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- illuminate/view: ^11.0|^12.0|^13.0
Requires (Dev)
- gsebastiao/laravel-auditable: ^1.0|^2.0
- gsebastiao/laravel-authz: ^3.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^2.0|^3.0|^4.0|^5.0
- pestphp/pest-plugin-laravel: ^2.0|^3.0|^4.0|^5.0
Suggests
- gsebastiao/laravel-auditable: Regista quem criou, editou, apagou ou restaurou cada item de menu. Depois de instalado, ativa com MENU_AUDITING_ENABLED=true.
- gsebastiao/laravel-authz: Grupos e permissões (RBAC). Uma vez instalado, o menu passa a esconder sozinho os itens que o utilizador não pode ver.
Provides
None
Conflicts
None
Replaces
None
README
Menus para Laravel guardados na base de dados, com os níveis que precisares (menu › submenu › sub-submenu…), que mostram a cada utilizador só o que ele pode ver.
- Funciona sem nenhum pacote de permissões — ou com o que já usas: gsebastiao/laravel-authz, Spatie, uma tabela tua.
- Rápido: a árvore fica em cache e a cache limpa-se sozinha quando mudas um item.
- Pronto a mostrar: um componente Blade desenha o menu com uma linha.
Índice
- Requisitos
- Começar em 5 minutos
- Criar itens de menu
- Mostrar o menu
- Permissões
- Proteger rotas (middleware)
- Cache
- Auditoria (opcional)
- Configuração
- Referência rápida
- Resolução de problemas
- Atualizar de uma versão anterior
- Testes
Requisitos
| Laravel | PHP |
|---|---|
| 11.x e 12.x | 8.2 ou mais recente |
| 13.x | 8.3 ou mais recente |
Começar em 5 minutos
1. Instala o pacote
composer require gsebastiao/laravel-menu
2. Cria a tabela menu_items
php artisan migrate
3. Cria alguns itens. Para experimentar, usa o menu de exemplo que vem com o pacote:
php artisan vendor:publish --tag=laravel-menu-seeders
php artisan db:seed --class=MenuItemsSeeder
O primeiro comando copia o exemplo para
database/seeders/MenuItemsSeeder.php, onde o podes editar. Podes correr o seeder as vezes que quiseres: os itens são atualizados, não duplicados.
4. Mostra o menu. No teu layout (ex.: resources/views/layouts/app.blade.php):
<nav> <x-laravel-menu::menu /> </nav>
Pronto: tens um menu a funcionar. Os itens do exemplo que apontam para rotas que ainda não existem no teu projeto aparecem sem link, sem erros.
Queres mudar alguma opção (permissões, cache, nome da tabela...)? Não precisas de publicar o config: basta acrescentar variáveis
MENU_*ao teu.env. A lista completa, com o padrão de cada uma, está em Configuração. Se fores mudar o nome da tabela (MENU_TABLE), faz isso antes domigrate.
5. (Opcional) Dá-lhe um estilo simples:
.menu, .menu-submenu { list-style: none; margin: 0; padding: 0; } .menu-submenu { padding-left: 1rem; } .menu-link { display: flex; align-items: center; gap: .5rem; padding: .4rem .75rem; color: inherit; text-decoration: none; border-radius: .375rem; } a.menu-link[href]:hover { background: #f1f5f9; } .menu-item.is-active > .menu-link { font-weight: 600; background: #e2e8f0; } .menu-badge { margin-left: auto; font-size: .75rem; padding: 0 .45rem; border-radius: 999px; background: #2563eb; color: #fff; } .menu-separator { border-top: 1px solid #e2e8f0; margin: .4rem 0; }
Criar itens de menu
Cada item é uma linha da tabela menu_items. Crias, editas e apagas itens como qualquer model do Laravel:
use Gsebastiao\LaravelMenu\Models\MenuItem; // Um item de topo que leva a uma rota MenuItem::create([ 'name' => 'dashboard', 'label' => 'Dashboard', 'route' => 'dashboard', 'order' => 1, ]); // Um grupo (sem link) com dois filhos $admin = MenuItem::create([ 'name' => 'admin', 'label' => 'Administração', 'order' => 2, ]); MenuItem::create([ 'parent_id' => $admin->id, 'name' => 'admin.users', 'label' => 'Utilizadores', 'route' => 'users.index', 'badge' => 'novo', ]); MenuItem::create([ 'parent_id' => $admin->id, 'name' => 'admin.separador', 'label' => '—', 'is_separator' => true, ]);
Podes pôr este código num seeder (como o de exemplo) ou experimentá-lo no php artisan tinker. A cache do menu é limpa automaticamente sempre que crias, editas, apagas ou restauras um item assim.
Os campos de um item
| Campo | Obrigatório | Para que serve | Exemplo |
|---|---|---|---|
name |
sim | Identificador interno do item. Usa um nome diferente para cada item. | 'admin.users' |
label |
sim | O texto que aparece no menu. | 'Utilizadores' |
parent_id |
não | O id do item pai. Vazio = item de topo. |
$admin->id |
route |
não | Para onde o item leva (ver tabela abaixo). Vazio = item sem link (ex.: um grupo). | 'users.index' |
params |
não | Parâmetros da rota. | ['user' => 5] |
order |
não (0) |
Posição entre os irmãos: os números menores aparecem primeiro. | 1 |
icon |
não | Classes CSS do ícone (do pacote de ícones que usas). | 'bi bi-people' |
badge |
não | Texto pequeno ao lado do nome. | 'novo' |
description |
não | Texto de ajuda (aparece ao passar o rato). | 'Gerir contas' |
target |
não | '_blank' abre o link num novo separador. |
'_blank' |
permission |
não | Permissão necessária para ver o item (ver Permissões). | 'users.view' |
is_active |
não (true) |
false esconde o item e todos os filhos dele. |
false |
is_separator |
não (false) |
Mostra uma linha divisória em vez de um link. | true |
O que pode ir no campo route
| Escreves | O item leva a… |
|---|---|
'users.index' |
a rota com esse nome (route('users.index', $params)) |
'/sobre' |
um caminho da tua aplicação (começa por /) |
'https://exemplo.com' |
um endereço externo (também mailto: e tel:) |
'#contactos' |
uma âncora na página |
Se o nome de rota não existir (ou faltar um parâmetro obrigatório), o item aparece sem link em vez de dar erro na página. Por segurança, endereços javascript: e data: nunca viram link.
Dica: num painel de administração, gere os itens com um CRUD normal (controller + formulário) sobre o model
MenuItem.
Mostrar o menu
Com o componente pronto
<x-laravel-menu::menu />
Mostra o menu do utilizador autenticado, já filtrado pelas permissões, com os submenus aninhados. Também aceita outros itens e atributos para a <ul> principal:
<x-laravel-menu::menu class="sidebar" id="menu-principal" /> <x-laravel-menu::menu :items="$outrosItens" />
O HTML gerado usa estas classes, para poderes dar-lhe o estilo que quiseres:
| Classe | Onde aparece |
|---|---|
menu |
cada <ul> do menu |
menu-submenu |
cada <ul> de um submenu |
menu-item |
cada <li> com um item |
is-active |
o <li> da página atual e dos seus pais (para abrires o submenu certo) |
has-children |
o <li> de um item com submenu |
menu-link |
o <a> de cada item (sem href quando o item não tem link) |
menu-icon, menu-label, menu-badge |
o ícone, o texto e o badge |
menu-separator |
o <li> de um separador |
Além das classes, o <a> da página atual leva aria-current="page", para que um leitor de ecrã a anuncie. Só esse: os itens-pai ficam apenas com a classe is-active.
Mudar o HTML do componente
Publica a view e edita a cópia (ex.: para usares as classes do Bootstrap ou do Tailwind):
php artisan vendor:publish --tag=laravel-menu-views
A cópia fica em resources/views/vendor/laravel-menu/components/menu.blade.php e passa a ser usada no lugar da original.
Montar o teu próprio HTML
Se preferires escrever tudo à mão, estas são as peças que o componente usa:
@foreach (Menu::forUser() as $item) <a href="{{ Menu::url($item) ?? '#' }}" @class(['active' => Menu::isActive($item)])> {{ $item['label'] }} </a> {{-- Os filhos estão em $item['children'] (com a mesma estrutura) --}} @endforeach
Menu::forUser()devolve os itens de topo que o utilizador pode ver. Cada item é um array com todos os campos da tabela e uma chavechildrencom os filhos.Menu::url($item)devolve o link do item, ounullse não tiver.Menu::isActive($item)diz se o item (ou um dos filhos) é a página atual. Um item com a rotausers.indextambém fica ativo emusers.create,users.edit, etc.
Permissões
Por omissão não há permissões: todos os itens aparecem a toda a gente. Para esconder itens, são dois passos.
Passo 1: escolhe o modo
No .env:
MENU_PERMISSION_MODE=string
| Modo | O que guardas no campo permission de cada item |
|---|---|
none |
Nada — as permissões são ignoradas (é o padrão). |
string |
O nome da permissão, ex.: users.view. |
id |
O id da permissão numa tabela tua, ex.: 42 (ver Modo id). |
Passo 2: diz ao pacote quais são as permissões do utilizador
Usas o gsebastiao/laravel-authz? Não precisas de fazer nada: salta para Com o gsebastiao/laravel-authz.
Usas o spatie/laravel-permission? Também não: o pacote usa $user->getAllPermissions() automaticamente.
Tens outra lógica? Define-a no boot() do app/Providers/AppServiceProvider.php:
use Gsebastiao\LaravelMenu\Facades\Menu; public function boot(): void { Menu::resolvePermissionsUsing(function ($user) { // Devolve os nomes das permissões (no modo 'id', os ids). return $user?->permissions()->pluck('name') ?? []; }); }
O $user é o utilizador autenticado (ou null para visitantes). Podes devolver um array ou uma Collection de textos, models, arrays ou enums (de um model ou array é lida a coluna name; no modo id, a coluna id).
Alternativa: indicar uma classe no config/menu.php
// config/menu.php 'user_permissions' => \App\Support\MenuPermissions::class,
// app/Support/MenuPermissions.php namespace App\Support; class MenuPermissions { public function __invoke($user): iterable { return $user?->permissions()->pluck('name') ?? []; } }
Não escrevas uma função (closure) diretamente no ficheiro de config: funciona, mas o php artisan config:cache deixa de funcionar.
Com o gsebastiao/laravel-authz
O gsebastiao/laravel-authz traz grupos e permissões (RBAC) ao teu projeto. Com ele instalado, o menu descobre-o sozinho — não escreves resolver nenhum.
1. Instala e prepara o pacote (se ainda não o fizeste):
composer require gsebastiao/laravel-authz php artisan authz:install
2. Põe o trait no teu model User:
use Gsebastiao\LaravelAuthz\Traits\HasAuthz; class User extends Authenticatable { use HasAuthz; }
3. Escolhe o modo string e guarda o nome da permissão em cada item:
MENU_PERMISSION_MODE=string
MenuItem::create([ 'name' => 'users', 'label' => 'Utilizadores', 'route' => 'users.index', 'permission' => 'users.view', // o nome da permissão, tal como está no laravel-authz ]);
É tudo. A partir daqui cada pessoa só vê o que pode, com a cascata do laravel-authz respeitada: negações individuais, regras dos grupos, validade por datas e o tenant atual. A cache do menu guarda a árvore, não as permissões de cada pessoa — quem perde uma permissão deixa de ver o item logo no pedido seguinte.
O middleware faz a mesma leitura, por isso a rota fica protegida com a mesma permissão que esconde o item:
Route::get('/utilizadores', [UserController::class, 'index']) ->middleware(['auth', 'menu.permission:users.view']);
Guardar o id da permissão em vez do nome
Se preferires que o campo permission guarde o id da permissão (sobrevive a uma mudança de nome), usa o modo id:
MENU_RESOLVER_KEY=id MENU_PERMISSION_MODE=id MENU_RESOLVER_COLUMN=permission MENU_RESOLVER_TABLE=auth_permissions
$item->resolvedPermissionLabel() passa a devolver o nome da permissão, lido da tabela auth_permissions. Com MENU_RESOLVER_COLUMN=label recebes antes o nome amigável (ex.: «Ver utilizadores»), que costuma ser o que queres mostrar num painel de administração.
Escolher a fonte das permissões em vez de a deixar ser descoberta
Sem configuração, o pacote procura por esta ordem: laravel-authz, depois $user->getAllPermissions() (Spatie). Para não deixar nada ao acaso, diz qual é no .env:
MENU_USER_PERMISSION=authz
Os valores aceites são auto (o padrão), authz e spatie. Se escolheres authz sem o pacote instalado, a aplicação pára no arranque com uma mensagem a explicar o que falta — em vez de esconder o menu todo em silêncio.
Duas notas: se o teu model User não tiver o trait HasAuthz, o menu lê as permissões à mesma, pelo id do utilizador; e um Menu::resolvePermissionsUsing(...) que tenhas escrito continua a ter a última palavra sobre tudo isto.
Quem vê o quê
| Situação | Resultado |
|---|---|
Item sem permission |
Aparece a todos. |
Item com permission |
Aparece só a quem tiver essa permissão. |
Item com is_active = false |
Não aparece a ninguém, nem os filhos. |
| Item cujo pai o utilizador não pode ver | Aparece na mesma, e o pai também (para não ficar um "buraco" na navegação). |
| Grupo sem link cujos filhos ficaram todos escondidos | Desaparece (não fica um grupo vazio). |
| Separador | Não conta como filho visível; separadores soltos (no início, no fim ou repetidos) são removidos. |
Verificar permissões no teu código
Menu::hasPermission('users.create'); // true / false Menu::hasPermission(['users.create', 'users.edit']); // true se tiver PELO MENOS UMA
@if (Menu::hasPermission('users.create')) <a href="{{ route('users.create') }}">Novo utilizador</a> @endif
No modo none, hasPermission() devolve sempre true.
Modo id
Usa este modo se o campo permission guardar ids de uma tabela tua. Indica a tabela no .env:
MENU_RESOLVER_KEY=id MENU_PERMISSION_MODE=id MENU_RESOLVER_COLUMN=name MENU_RESOLVER_TABLE=permissions
- O resolver de permissões (passo 2) deve devolver os ids das permissões do utilizador.
$item->resolvedPermissionLabel()devolve o nome legível da permissão do item, lido dessa tabela (útil num painel de administração).- Com o gsebastiao/laravel-authz, os valores certos são
auth_permissions/id/permission— ver Com o gsebastiao/laravel-authz.
Proteger rotas (middleware)
O pacote regista o middleware menu.permission:
Route::get('/utilizadores', [UserController::class, 'index']) ->middleware(['auth', 'menu.permission:users.view']); // Com várias permissões, basta ter UMA delas: Route::get('/relatorios', [ReportController::class, 'index']) ->middleware(['auth', 'menu.permission:reports.view,reports.export']);
- Quem não tiver a permissão recebe um erro 403.
- No modo
none, o middleware deixa passar sempre — o mesmo código serve para projetos com e sem permissões. - Junta-o ao middleware
auth, para que um visitante seja enviado para o login em vez de receber um 403.
Cache
A árvore do menu é guardada em cache e limpa-se sozinha quando um item é criado, editado, apagado ou restaurado através do model (create(), update(), save(), delete(), restore()).
A cache não é limpa sozinha quando alteras os itens por outras vias:
- updates em massa:
MenuItem::where(...)->update([...]); saveQuietly(),updateQuietly()ouMenuItem::withoutEvents(...);- alterações diretas na base de dados (SQL,
DB::table(...), outra aplicação).
Nesses casos, limpa-a à mão:
php artisan laravel-menu:cache # reconstrói a cache
php artisan laravel-menu:cache --flush # só limpa
Menu::flushCache(); // limpa Menu::rebuildCache(); // limpa e volta a guardar
As opções da cache ficam no .env (ver a tabela em Configuração):
MENU_CACHE_ENABLED=true MENU_CACHE_STORE=redis MENU_CACHE_TTL=3600
Auditoria (opcional)
Com o pacote gsebastiao/laravel-auditable, fica registado quem criou, editou, apagou ou restaurou cada item de menu, quando e o que mudou. O laravel-menu não depende desse pacote: só o instalas se quiseres.
1. Instala o pacote de auditoria:
composer require gsebastiao/laravel-auditable
php artisan migrate
O pacote de auditoria traz a própria migration e o migrate a executa: não precisas de publicar nada. (Só publica o config ou a migration se os quiseres editar — vê o README do laravel-auditable.)
2. Liga a auditoria no .env:
MENU_AUDITING_ENABLED=true
Não tens de mudar mais nada: MenuItem::create(), $item->update(), $item->delete() e $item->restore() passam a ficar registados. Em vez do parent_id, a auditoria guarda o nome do item pai.
$item->audits; // histórico deste item
Se ligares a auditoria sem o pacote instalado, a aplicação pára no arranque com uma mensagem a explicar como instalá-lo. Assim nunca ficas a pensar que a auditoria está a gravar quando não está.
Mudar o que é gravado
Cria um model teu que estenda o MenuItem e sobrescreve getAuditOptions():
namespace App\Models; use Gsebastiao\Auditable\Support\AuditOptions; use Gsebastiao\LaravelMenu\Models\MenuItem as BaseMenuItem; class MenuItem extends BaseMenuItem { public function getAuditOptions(): AuditOptions { return parent::getAuditOptions()->except(['badge', 'order']); } }
Indica-o no config/menu.php ('model' => \App\Models\MenuItem::class) e usa-o no teu código. Se quiseres os métodos extra do laravel-auditable (auditAction(), operations()…), acrescenta use \Gsebastiao\Auditable\Concerns\Auditable; a essa classe — o laravel-menu deteta-o e não grava nada em duplicado.
Configuração
Tudo funciona sem configurar nada, e não precisas de publicar o ficheiro de configuração. Para mudar alguma coisa, usa o .env:
| Variável | Padrão | Para que serve |
|---|---|---|
MENU_TABLE |
menu_items |
Nome da tabela (muda antes do migrate) |
MENU_MODEL |
Gsebastiao\LaravelMenu\Models\MenuItem |
Model dos itens (uma classe tua que estenda o do pacote) |
MENU_PERMISSION_MODE |
none |
none, string ou id (Permissões) |
MENU_RESOLVER_TABLE |
auth_permissions |
Tabela de permissões (só no modo id) |
MENU_RESOLVER_KEY |
id |
Coluna comparada com o campo permission (só no modo id) |
MENU_RESOLVER_COLUMN |
name |
Coluna com o nome legível da permissão (com o laravel-authz: permission ou label) |
MENU_USER_PERMISSION |
(não definir) | Fonte das permissões do utilizador: auto (o padrão), authz, spatie, ou uma classe com __invoke($user) |
MENU_CACHE_ENABLED |
true |
Liga/desliga a cache |
MENU_CACHE_STORE |
(não definir) | Cache a usar (sem valor = a padrão da aplicação) |
MENU_CACHE_TTL |
(não definir) | Validade da cache em segundos (sem valor ou 0 = sem prazo) |
MENU_CACHE_KEY |
laravel_menu |
Prefixo da chave na cache |
MENU_AUDITING_ENABLED |
false |
Liga a auditoria |
Não deixes uma variável em branco (
MENU_CACHE_STORE=): o Laravel lê isso como texto vazio. Para voltar ao padrão, apaga a linha. Comphp artisan config:cache, corre-o de novo depois de mudar o.env.
Se preferires editar o ficheiro, publica a configuração:
php artisan vendor:publish --tag=laravel-menu-config
Tudo o que podes publicar:
| Comando | Cria |
|---|---|
php artisan vendor:publish --tag=laravel-menu-config |
config/menu.php |
php artisan vendor:publish --tag=laravel-menu-views |
resources/views/vendor/laravel-menu/components/menu.blade.php |
php artisan vendor:publish --tag=laravel-menu-seeders |
database/seeders/MenuItemsSeeder.php |
php artisan vendor:publish --tag=laravel-menu-migrations |
a migration, em database/migrations/ (só se a quiseres alterar) |
Referência rápida
Facade Menu (use Gsebastiao\LaravelMenu\Facades\Menu; — nas views Blade já está disponível):
| Método | O que faz |
|---|---|
Menu::forUser($user = null) |
Itens que o utilizador pode ver, prontos a mostrar. Sem argumentos usa o utilizador autenticado. |
Menu::forUser(null, ['a', 'b']) |
O mesmo, para uma lista de permissões que indicas. |
Menu::tree() |
Todos os itens ativos, sem filtrar permissões. |
Menu::url($item) |
Link do item, ou null. |
Menu::isActive($item) |
true se o item ou um dos filhos é a página atual. |
Menu::hasPermission('a') |
true se o utilizador tiver a permissão (ou uma de várias). |
Menu::resolvePermissionsUsing(fn ($user) => ...) |
Define como obter as permissões do utilizador. |
Menu::resolveUserPermissions($user = null) |
As permissões do utilizador, tal como o pacote as vê (útil para depurar). |
Menu::rebuildCache() / Menu::flushCache() |
Reconstrói / limpa a cache. |
Menu::cacheEnabled() |
A cache está ligada? (o mesmo que config('menu.cache.enabled'), com o padrão aplicado). |
Model MenuItem:
| Uso | O que faz |
|---|---|
$item->parent, $item->children |
Pai e filhos diretos (pela ordem do menu). |
$item->childrenRecursive |
Todos os descendentes, carregados de uma vez. |
MenuItem::active(), ::roots(), ::ordered() |
Só ativos / só de topo / pela ordem do menu. |
$item->isVisibleTo($permissoes) |
O item é visível com estas permissões? |
$item->resolvedPermissionLabel() |
Nome legível da permissão (no modo id, lido da tua tabela). |
$item->audits |
Histórico de auditoria (requer o laravel-auditable). |
Comando: php artisan laravel-menu:cache (com --flush só limpa).
Resolução de problemas
O menu aparece vazio.
Confirma que há itens com is_active = true. Se usas permissões, vê o que o pacote recebe com dd(Menu::resolveUserPermissions()) — se vier vazio, revê o passo 2 das permissões.
Instalei o gsebastiao/laravel-authz e o menu continua vazio.
Confirma três coisas: o MENU_PERMISSION_MODE está em string (ou em id, se guardares ids); o campo permission de cada item é exatamente igual ao nome da permissão no auth_permissions (a comparação distingue maiúsculas de minúsculas); e a permissão chega mesmo ao utilizador — dd(Menu::resolveUserPermissions()) mostra o que o pacote está a ver.
Alterei itens e o menu não mudou.
Provavelmente alteraste-os sem passar pelos eventos do model (update em massa, SQL direto…). Corre php artisan laravel-menu:cache. Ver Cache.
Um item aparece sem link.
O nome de rota no campo route não existe (confirma com php artisan route:list), falta um parâmetro obrigatório em params, ou é um caminho sem / no início (usa /sobre, não sobre).
O super-administrador não vê todos os itens.
O pacote compara listas de permissões e não passa pelo Gate. Faz o resolver devolver todas as permissões nesse caso:
Menu::resolvePermissionsUsing(function ($user) { if ($user?->hasRole('super-admin')) { return \Spatie\Permission\Models\Permission::pluck('name'); } return $user?->getAllPermissions() ?? []; });
php artisan config:cache falha com "Your configuration files are not serializable".
Tens uma closure no config/menu.php (normalmente em user_permissions). Troca-a por Menu::resolvePermissionsUsing() ou por uma classe — ver Permissões.
Target class [Database\Seeders\MenuItemsSeeder] does not exist.
O seeder foi publicado por uma versão anterior a 2.1, que o copiava com o namespace errado. Publica-o de novo: php artisan vendor:publish --tag=laravel-menu-seeders --force.
Erro no arranque: "A auditoria do laravel-menu está ativada … mas o pacote … não está instalado".
Instala o pacote de auditoria (ver Auditoria) ou define MENU_AUDITING_ENABLED=false.
Erro: "Valor inválido em config('menu.permission_mode')".
O MENU_PERMISSION_MODE tem um valor desconhecido (ex.: strings). Usa none, string ou id.
Atualizar de uma versão anterior
De 2.1 para 2.2
Não há passos obrigatórios. Uma única coisa a rever: se já tens o gsebastiao/laravel-authz instalado e não configuraste nenhum resolver de permissões, o menu deixa de esconder todos os itens com permission e passa a mostrar os que cada pessoa pode ver — ver Com o gsebastiao/laravel-authz. Se tens um Menu::resolvePermissionsUsing(...) ou uma classe em config('menu.user_permissions'), nada muda.
De 2.0 para 2.1
Não há passos obrigatórios. Revê apenas:
- Se publicaste o seeder na 2.0, publica-o de novo:
php artisan vendor:publish --tag=laravel-menu-seeders --force(a cópia antiga tinha o namespace errado). - Middleware com várias permissões:
menu.permission:a,bpassou a aceitar quem tiveraoub(antes sóaera verificada). - Menus filtrados: grupos sem link que ficam vazios e separadores soltos deixaram de aparecer.
MENU_PERMISSION_MODEcom um valor desconhecido passa a dar erro (antes funcionava comostringsem avisar).
O CHANGELOG tem a lista completa.
De 1.x (gsebastiao/laravel-dynamic-menu) para 2.x
Na 2.0 o pacote mudou de nome. A tabela e os dados não mudam, e a migration não volta a correr.
-
Troca o pacote:
composer remove gsebastiao/laravel-dynamic-menu
composer require gsebastiao/laravel-menu
-
No teu código, substitui
Gsebastiao\DynamicMenu\porGsebastiao\LaravelMenu\. -
Se publicaste a config, renomeia
config/dynamic-menu.phpparaconfig/menu.phpe trocaconfig('dynamic-menu.…')porconfig('menu.…'). -
No
.env, troca o prefixoDYNAMIC_MENU_porMENU_(ex.:DYNAMIC_MENU_PERMISSION_MODE→MENU_PERMISSION_MODE). -
Modo
idsem config publicada: a tabela padrão passou depermissionsparaauth_permissions. Se usaspermissions, defineMENU_RESOLVER_TABLE=permissions. -
Nos scripts de deploy, troca
php artisan dynamic-menu:cacheporphp artisan laravel-menu:cache, e as tagsdynamic-menu-*dovendor:publishporlaravel-menu-*. -
Corre
php artisan laravel-menu:cache(a chave da cache mudou dedynamic_menuparalaravel_menu).
Testes
composer install
composer test
A suíte usa Pest com Orchestra Testbench e corre no CI com Laravel 11, 12 e 13, em PHP 8.2 a 8.4, com e sem o pacote de auditoria.
Licença
MIT. Ver LICENSE.