PHPackages                             gsebastiao/laravel-dynamic-menu - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. gsebastiao/laravel-dynamic-menu

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

gsebastiao/laravel-dynamic-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.

v1.0.0(1mo ago)02MITPHPPHP ^8.2CI failing

Since Jul 11Pushed 1w agoCompare

[ Source](https://github.com/gsebastiao/laravel-dynamic-menu)[ Packagist](https://packagist.org/packages/gsebastiao/laravel-dynamic-menu)[ Docs](https://github.com/gsebastiao/laravel-dynamic-menu)[ RSS](/packages/gsebastiao-laravel-dynamic-menu/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (6)Versions (2)Used By (0)

Laravel Menu
============

[](#laravel-menu)

Menus **dinâmicos e hierárquicos** (N níveis) para Laravel, com controlo de permissões **flexível** e cache para leitura rápida sem joins.

O pacote é **100% independente**: não depende de Spatie nem de nenhum outro pacote de permissões. Podes usá-lo num projeto simples **sem permissões**, com **permissões por string**, ou apontando para **qualquer tabela** de permissões do teu projeto.

[![tests](https://github.com/gsebastiao/laravel-menu/actions/workflows/tests.yml/badge.svg)](https://github.com/gsebastiao/laravel-menu/actions)[![Latest Version](https://camo.githubusercontent.com/c7dfb6ffdd07885bb0063d8971c53f1dc1c04f47ac31c37465c250e587b28c1a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6773656261737469616f2f6c61726176656c2d6d656e752e737667)](https://packagist.org/packages/gsebastiao/laravel-menu)[![License](https://camo.githubusercontent.com/84d3568237900bc47aa3377509c28a795e3193c3d9e0660995bfbbcff9748155/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6773656261737469616f2f6c61726176656c2d6d656e752e737667)](LICENSE)

---

Índice
------

[](#índice)

- [Requisitos](#requisitos)
- [Instalação](#instala%C3%A7%C3%A3o)
- [Conceito central: os três modos de permissão](#conceito-central-os-tr%C3%AAs-modos-de-permiss%C3%A3o)
- [Configuração](#configura%C3%A7%C3%A3o)
- [Estrutura de um item de menu](#estrutura-de-um-item-de-menu)
- [Uso](#uso)
    - [Ler a árvore completa](#ler-a-%C3%A1rvore-completa)
    - [Filtrar pela permissão do utilizador](#filtrar-pela-permiss%C3%A3o-do-utilizador)
    - [Renderizar em Blade](#renderizar-em-blade)
    - [Criar itens](#criar-itens)
- [Modos de permissão em detalhe](#modos-de-permiss%C3%A3o-em-detalhe)
- [Middleware](#middleware)
- [Cache](#cache)
- [Seeder](#seeder)
- [Testes](#testes)
- [Licença](#licen%C3%A7a)

---

Requisitos
----------

[](#requisitos)

PacoteVersãoPHP^8.2Laravel11, 12 ou 13> **Nota sobre Laravel 13 e PHP:** o Laravel 13 exige **PHP 8.3** no mínimo. Além disso, algumas versões de patch (13.3+) puxam componentes do Symfony 8 que exigem **PHP 8.4**. Se estiveres em PHP 8.3, considera fixar `laravel/framework:^13.0  env('MENU_PERMISSION_MODE', 'none'),

    // Usado apenas no modo 'id'. Aponta para QUALQUER tabela do teu projeto.
    'resolver' => [
        'table'  => 'permissions',
        'key'    => 'id',
        'column' => 'name',
    ],

    // Callback opcional que devolve as permissões do utilizador.
    // null => o pacote tenta $user->getAllPermissions() e faz fallback para [].
    'user_permissions' => null,

    'cache' => [
        'enabled' => true,
        'store'   => null,   // null = store default (podes pôr 'redis')
        'key'     => 'laravel_menu',
        'ttl'     => null,   // null = forever
    ],

    'table' => 'menu_items',
    'model' => \Gsebastiao\LaravelMenu\Models\MenuItem::class,
];
```

---

Estrutura de um item de menu
----------------------------

[](#estrutura-de-um-item-de-menu)

CampoTipoDescrição`id`bigintPK`parent_id`bigint, nullPai na hierarquia (N níveis)`name`stringIdentificador interno/máquina (ex.: `admin.users`)`label`stringTexto exibido`description`string, nullDescrição opcional`route`string, nullNome de rota, URL ou caminho`icon`string, nullÍcone`permission`string, nullPermissão (interpretação depende do modo)`order`intOrdenação`target`string, null`_self`, `_blank`, etc.`is_active`boolAtivo/inativo`is_separator`boolItem separador (linha)`badge`string, nullBadge (ex.: `novo` ou um contador)`params`json, nullParâmetros de rota ou metadados`timestamps`—`created_at` / `updated_at``deleted_at`—Soft delete---

Uso
---

[](#uso)

### Ler a árvore completa

[](#ler-a-árvore-completa)

Devolve **todos** os itens ativos, já aninhados, servidos da cache (sem joins):

```
use Gsebastiao\LaravelMenu\Facades\Menu;

$tree = Menu::tree();
// Collection de arrays; cada nó tem uma chave 'children' (array)
```

### Filtrar pela permissão do utilizador

[](#filtrar-pela-permissão-do-utilizador)

Devolve apenas os itens que o utilizador pode ver, de acordo com o modo configurado. Um pai é mantido se tiver filhos visíveis (evita "buracos" na navegação):

```
// Utilizador autenticado
$menu = Menu::forUser();

// Um utilizador específico
$menu = Menu::forUser($user);

// Ou passando as permissões diretamente
$menu = Menu::forUser(null, ['user.create', 'admin.access']);
```

No modo `none`, `forUser()` devolve simplesmente a árvore completa.

### Renderizar em Blade

[](#renderizar-em-blade)

Cada nó é um array. Exemplo recursivo simples:

```
{{-- resources/views/partials/menu.blade.php --}}

    @foreach ($items as $item)
        @if ($item['is_separator'])

        @else

                    @if ($item['icon'])  @endif
                    {{ $item['label'] }}
                    @if ($item['badge']) {{ $item['badge'] }} @endif

                @if (!empty($item['children']))
                    @include('partials.menu', ['items' => $item['children']])
                @endif

        @endif
    @endforeach

```

```
{{-- No layout --}}
@include('partials.menu', ['items' => \Gsebastiao\LaravelMenu\Facades\Menu::forUser()])
```

### Criar itens

[](#criar-itens)

```
use Gsebastiao\LaravelMenu\Models\MenuItem;

$admin = MenuItem::create([
    'name'       => 'admin',
    'label'      => 'Administração',
    'icon'       => 'shield',
    'order'      => 1,
    'permission' => 'admin.access', // no modo 'id' seria o id, ex.: '42'
]);

MenuItem::create([
    'parent_id'  => $admin->id,
    'name'       => 'admin.users',
    'label'      => 'Utilizadores',
    'route'      => 'admin.users.index',
    'order'      => 1,
    'permission' => 'users.view',
    'badge'      => 'novo',
    'params'     => ['tab' => 'active'],
]);
```

A cache é invalidada automaticamente sempre que gravas, apagas ou restauras um item.

---

Modos de permissão em detalhe
-----------------------------

[](#modos-de-permissão-em-detalhe)

### Modo `none` (default)

[](#modo-none-default)

Nada a configurar. O campo `permission` é ignorado, `Menu::tree()` e `Menu::forUser()` devolvem tudo, e o middleware deixa passar sempre. Ideal para projetos simples.

```
// config/menu.php
'permission_mode' => 'none',
```

### Modo `string`

[](#modo-string)

Guardas a permissão como texto. Por omissão, o pacote obtém as permissões do utilizador via `$user->getAllPermissions()` (compatível com vários setups, incluindo Spatie) e compara as strings. Podes personalizar com o callback `user_permissions`:

```
'permission_mode' => 'string',

'user_permissions' => function ($user) {
    // devolve um array/Collection de strings
    return $user?->permissions()->pluck('name')->all() ?? [];
},
```

```
$menu = Menu::forUser($user); // já filtrado pelas permissões do $user
```

### Modo `id`

[](#modo-id)

Guardas o **id** da permissão (como texto) e apontas o resolver para a tua tabela. O pacote resolve o id contra ela quando precisa do rótulo legível, e compara ids na filtragem:

```
'permission_mode' => 'id',

'resolver' => [
    'table'  => 'permissions', // a TUA tabela
    'key'    => 'id',
    'column' => 'name',
],

'user_permissions' => function ($user) {
    // devolve os IDS das permissões do utilizador
    return $user?->permissions()->pluck('id')->all() ?? [];
},
```

Obter o rótulo legível de um item:

```
$item->resolvedPermissionLabel(); // ex.: 'gerir.tudo' (lido da tua tabela)
```

---

Middleware
----------

[](#middleware)

O pacote regista o alias `menu.permission`. Protege rotas exigindo uma permissão:

```
Route::get('/admin', [AdminController::class, 'index'])
    ->middleware('menu.permission:admin.access');
```

- No modo `none`, o middleware é um **no-op** (deixa passar sempre) — o mesmo código funciona em projetos com e sem permissões.
- Nos modos `string`/`id`, devolve **403** se o utilizador não tiver a permissão indicada.

---

Cache
-----

[](#cache)

A árvore é lida da cache, sem joins. Configura o store em `config/menu.php`:

```
'cache' => [
    'enabled' => true,
    'store'   => 'redis', // ou null para o default, 'file', etc.
    'ttl'     => 3600,    // segundos; null = forever
],
```

A cache é invalidada automaticamente em `saved` / `deleted` / `restored` do model. Para gerir manualmente:

```
# Reconstruir a cache
php artisan laravel-menu:cache

# Apenas limpar
php artisan laravel-menu:cache --flush
```

Ou por código:

```
Menu::rebuildCache();
Menu::flushCache();
```

---

Seeder
------

[](#seeder)

O pacote inclui um seeder de exemplo com uma hierarquia de várias profundidades. Publica-o e adapta:

```
php artisan vendor:publish --tag=laravel-menu-seeders
```

Depois corre:

```
// database/seeders/DatabaseSeeder.php
$this->call(\Database\Seeders\MenuItemsSeeder::class);
```

```
php artisan db:seed --class="Database\\Seeders\\MenuItemsSeeder"
```

Ou usa diretamente o seeder do pacote sem publicar:

```
php artisan db:seed --class="Gsebastiao\\LaravelMenu\\Database\\Seeders\\MenuItemsSeeder"
```

---

Testes
------

[](#testes)

O pacote usa [Pest](https://pestphp.com/) com [Orchestra Testbench](https://github.com/orchestral/testbench).

```
composer install
vendor/bin/pest
```

A suite cobre: montagem da árvore em N níveis, ordenação, cache e sua invalidação, filtragem por permissão nos três modos, resolução via tabela no modo `id`, o middleware e o comando artisan.

---

Licença
-------

[](#licença)

MIT. Ver [LICENSE](LICENSE).

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance94

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

48d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/aab336e4460b96481b6b91cc9b0b101959b827f766ab3ac08b77496b9076b32f?d=identicon)[gsebastiao](/maintainers/gsebastiao)

---

Top Contributors

[![gsebastiao](https://avatars.githubusercontent.com/u/246223043?v=4)](https://github.com/gsebastiao "gsebastiao (2 commits)")

---

Tags

laraveltreemenupermissionsnavigationhierarchicaldynamic menu

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/gsebastiao-laravel-dynamic-menu/health.svg)

```
[![Health](https://phpackages.com/badges/gsebastiao-laravel-dynamic-menu/health.svg)](https://phpackages.com/packages/gsebastiao-laravel-dynamic-menu)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M342](/packages/laravel-ai)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k161.4k2](/packages/mike-bronner-laravel-model-caching)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1614.1k4](/packages/masterix21-laravel-licensing)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

265.2k](/packages/aedart-athenaeum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
