Tutorial Laravel 13 #4: painel de administração com Filament
verificado a 7 Setembro 2026 · 7 min
O Laravel não fornece back-office. Esta série passa a usar o Filament: composer require filament/filament e depois php artisan filament:install --panels. O Voyager, usado nas versões anteriores, está marcado como abandonado no Packagist e já não se instala em Laravel 13.
O Laravel não fornece back-office. Tens de escolher um, e essa escolha compromete o projeto durante anos. Este capítulo explica por que razão esta série mudou de pacote e instala depois o Filament.
Porque é que este capítulo mudou
As versões anteriores deste tutorial usavam o Voyager. Já não é sustentável.
tcg/voyager está marcado como abandonado no Packagist. A última versão, a 1.8.0, data de setembro de 2024 e declara uma compatibilidade que termina no Laravel 11. Num projeto Laravel 13, o Composer recusa-se simplesmente a instalá-lo: bloqueia primeiro nos avisos de segurança que atingem todas as suas versões, e a restrição ao Laravel 11 faria de qualquer forma falhar a resolução.
É essa a lição útil do episódio: um tutorial assente num pacote mantido por uma só equipa passa a estar errado no dia em que essa equipa para. A escolha do substituto tem, por isso, de pesar a saúde do projeto tanto quanto as suas funcionalidades.
O que foi analisado
Quatro pistas, medidas a 2 de setembro de 2026 sobre os dados públicos do Packagist:
| Pacote | Última versão | Laravel 13 | Downloads / mês |
|---|---|---|---|
tcg/voyager | 1.8.0 (set. 2024) | não | 23 614, mas abandonado |
ilsondev/voyager | 2.2.1 (jul. 2026) | sim | 1 |
orchid/platform | 14.53.0 (mar. 2026) | sim | 27 227 |
filament/filament | 5.7.8 (ago. 2026) | sim | 3 324 015 |
O ilsondev/voyager é um fork que funciona: foi instalado num Laravel 13.30.1 acabado de criar para esta revisão, e o dashboard, a ferramenta BREAD, a mediateca, o construtor de menus e as definições respondem todos como devem. Mas soma 12 downloads e uma estrela, e todas as suas versões foram publicadas em três dias de julho de 2026. Puxa ainda o intervention/image na versão 2, cujo ramo já não é o ramo atual. Recomendar este fork a um principiante seria repetir exatamente o erro que partiu este tutorial.
Dito isto, se manténs uma aplicação Voyager já existente e o que procuras é passar para Laravel 13 sem reescrever tudo, este fork é uma ponte honesta. Trata-o como uma etapa, não como um destino.
A escolha: Filament
O Filament ganha por três razões.
- Não desaparece amanhã. 3,3 milhões de downloads por mês, cem vezes a audiência de todas as alternativas juntas, e versões publicadas todas as semanas.
- O back-office é código. O Voyager guardava a configuração dos ecrãs na base de dados, clicada numa interface. No Filament, cada ecrã é uma classe PHP versionada com o resto do projeto. Lê-se, compara-se e faz-se o deploy dela como de qualquer outro ficheiro.
- É uma competência que serve. O Filament é hoje o back-office por omissão do ecossistema Laravel. O que aprendes aqui vais voltar a encontrá-lo num projeto a sério.
Vale a pena conhecer duas alternativas pagas, ainda que não sejam necessárias para este tutorial: o Nova, a solução oficial da equipa Laravel, e o Backpack.
Instalar o Filament
A extensão intl tem de estar presente
O Filament exige a extensão PHP intl. Confirma que a tens antes de instalar:
php -m | grep intlSe o comando não devolver nada, a instalação falha com esta mensagem, que não menciona o Filament e deixa qualquer um perplexo:
filament/support[...] require ext-intl * -> it is missing from your system.
Install or enable PHP's intl extension.O primeiro capítulo já aconselhava a verificá-la por esta razão. Em Debian ou Ubuntu, sudo apt install php8.4-intl. Em macOS com o Homebrew, a extensão já lá está. Em Windows com o WampServer, desmarca e volta a marcar php_intl no menu das extensões PHP. Reinicia depois o servidor.
O pacote e o painel
composer require filament/filament
php artisan filament:install --panelsO segundo comando cria app/Providers/Filament/AdminPanelProvider.php, publica os ficheiros CSS e JavaScript do painel em public e esvazia as caches.
INFO Successfully published assets!
INFO Successfully upgraded!Criar uma conta
php artisan make:filament-userO comando pede um nome, um endereço de e-mail e uma palavra-passe, e depois confirma:
INFO Success! admin@gekkode.test may now log in at http://localhost:8000/admin/login.Vai a http://127.0.0.1:8000/admin e inicia sessão. O dashboard está vazio: é normal, ainda não lhe foi confiado nada. O capítulo 6 vai acrescentar-lhe os artigos, as categorias e as etiquetas.
Controlar quem entra
Em ambiente local, o Filament deixa entrar qualquer utilizador autenticado. Em todo o resto, recusa toda a gente com um erro 403 enquanto o modelo User não disser quem tem direito a entrar. É uma segurança por omissão, mas apanha-te desprevenido: o painel funciona na tua máquina e devolve 403 assim que o site vai para o ar.
A regra declara-se implementando a interface FilamentUser. Mantenha tudo o que o modelo fornecido já contém, os atributos #[Fillable] e #[Hidden] tal como o método casts(): só a interface e o método canAccessPanel() se acrescentam.
<?php
namespace App\Models;
use Database\Factories\UserFactory;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<UserFactory> */
use HasFactory, Notifiable;
public function canAccessPanel(Panel $panel): bool
{
return str_ends_with($this->email, '@gekkode.test');
}
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}Substitui o domínio pelo teu. Esta regra é propositadamente simplista: chega para um projeto de aprendizagem, não para um site público. Um projeto a sério assenta numa coluna is_admin ou num sistema de papéis.
O comportamento verifica-se com dois testes. O segundo conta tanto como o primeiro: em ambiente de teste, o Filament recusa toda a gente enquanto a regra não existir, pelo que um teste que só verificasse a recusa passaria mesmo sem ela.
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AdminTest extends TestCase
{
use RefreshDatabase;
public function test_un_email_hors_domaine_est_refuse(): void
{
$user = User::factory()->create(['email' => 'intrus@example.com']);
$this->actingAs($user)->get('/admin')->assertForbidden();
}
public function test_un_email_du_domaine_est_accepte(): void
{
$user = User::factory()->create(['email' => 'admin@gekkode.test']);
$this->actingAs($user)->get('/admin')->assertOk();
}
}Migrar a partir da versão Voyager deste tutorial
Se seguiste este tutorial na sua versão Voyager, eis o que muda.
- As tabelas do Voyager desaparecem. A instalação criava dez:
data_types,data_rows,menus,menu_items,settings,roles,permissions,permission_role,user_rolesetranslations. Nenhuma serve para alguma coisa. As tuas tabelas de negócio,posts,categories,tags,post_tag,users, ficam tal como estão: o Filament liga-se a elas sem migração de dados. - A configuração BREAD perde-se, e é de propósito. O que tinhas clicado no Voyager reescreve-se em PHP, uma vez, nos ficheiros do capítulo 6. É meia hora de trabalho, ao fim da qual a configuração fica versionada.
- A função
setting()deixa de existir. O Voyager fornecia-a para ler o título e a descrição do site. Substituisetting('site.title')porconfig('app.name'), ou pelas tuas próprias definições. - O contorno do slug
postsdeixa de fazer falta. O Voyager trazia o seu próprio modeloPost, o que obrigava a mudar o slug da tabela parablog-postse a corrigir um template do pacote. O Filament não impõe modelo nenhum, o conflito desaparece. - O endereço do back-office não muda. O Filament instala-se também em
/admin.
Para retirar o Voyager de um projeto existente: composer remove tcg/voyager, depois apaga as suas tabelas e a pasta resources/views/vendor/voyager, se existir. Faz antes uma cópia de segurança da base de dados.
O que este capítulo não tratou
Os papéis e permissões finos, a personalização do tema do painel e os widgets do dashboard ultrapassam o âmbito desta série. A documentação do Filament cobre-os.
O capítulo seguinte constrói a página inicial do site público.