Een Filament resource is één PHP-klasse die een Eloquent-model koppelt aan een complete CRUD-interface: een table voor het overzicht, een form voor aanmaken en bewerken, en optioneel een infolist voor de detailpagina. Met één artisan-commando heb je in Filament v4 en v5 vijf bestanden en een...
Een Filament resource is één PHP-klasse die een Eloquent-model koppelt aan een complete CRUD-interface: een table voor het overzicht, een form voor aanmaken en bewerken, en optioneel een infolist voor de detailpagina. Met één artisan-commando heb je in Filament v4 en v5 vijf bestanden en een werkend beheerscherm.
Dit artikel legt de zes bouwstenen uit die je in elk Filament-project tegenkomt: resources, schemas en forms, tables, infolists, actions en relation managers. Met korte codevoorbeelden die kloppen voor de v4/v5-API. Onze eigen backoffice voor blog, leads, afspraken en cases draait op Filament. Wat hieronder staat, gebruiken wij dagelijks.
Nog niet bekend met Filament zelf? Begin dan bij wat Filament PHP is of op onze Filament-pagina.
Wat is een Filament resource?
Een resource is de centrale klasse die bepaalt hoe een model eruitziet en zich gedraagt in je admin panel. Hij bundelt form, table, pagina's en relaties op één plek.
Je genereert er een met:
php artisan make:filament-resource Customer --generate
De vlag --generate leest je databasekolommen en vult form en table alvast in. Andere nuttige vlaggen:
--viewvoegt een aparte View-pagina toe (met infolist).--simplemaakt een resource met één Manage-pagina, waarbij aanmaken en bewerken in een modal gebeuren.--soft-deletesvoegt filters en acties toe voor soft-deleted records.
Sinds v4 genereert Filament een nettere mappenstructuur. Form en table staan in eigen klassen:
app/Filament/Resources/
└── Customers/
├── CustomerResource.php
├── Pages/
│ ├── CreateCustomer.php
│ ├── EditCustomer.php
│ └── ListCustomers.php
├── Schemas/
│ └── CustomerForm.php
└── Tables/
└── CustomersTable.php
De resource zelf blijft daardoor kort. Hij delegeert naar die klassen:
use App\Filament\Resources\Customers\Schemas\CustomerForm;
use App\Filament\Resources\Customers\Tables\CustomersTable;
use Filament\Schemas\Schema;
use Filament\Tables\Table;
class CustomerResource extends Resource
{
protected static ?string $model = Customer::class;
protected static ?string $recordTitleAttribute = 'name';
public static function form(Schema $schema): Schema
{
return CustomerForm::configure($schema);
}
public static function table(Table $table): Table
{
return CustomersTable::configure($table);
}
public static function getPages(): array
{
return [
'index' => ListCustomers::route('/'),
'create' => CreateCustomer::route('/create'),
'edit' => EditCustomer::route('/{record}/edit'),
];
}
}
$recordTitleAttribute bepaalt welke kolom Filament gebruikt als titel van een record, onder meer in global search en breadcrumbs.
Wat zijn schemas in Filament v4 en v5?
Een schema is de container waarin je velden, entries en layout-componenten plaatst. In v4 heeft Filament forms en infolists samengevoegd onder één Schema-klasse.
In v3 had je een aparte Form en Infolist. Nu krijgt zowel form() als infolist() een Filament\Schemas\Schema binnen. Dat heeft twee praktische gevolgen:
- Layout-componenten zoals
Section,Grid,TabsenFieldsetstaan nu inFilament\Schemas\Components, niet meer inFilament\Forms\Components. - Je kunt formuliervelden en read-only entries in hetzelfde schema mixen.
v5 verandert hier niets aan. Die release bracht alleen Livewire 4-support; de API is gelijk aan v4. Wie van v3 komt, merkt de namespace-wijzigingen wel direct. Zie upgraden van Filament 3 naar 5 voor de valkuilen, en wat er nieuw is in Filament 4 en 5 voor het complete overzicht.
Hoe bouw je een Filament form?
Een Filament form is een schema met invoervelden. Elk veld koppel je via make('kolomnaam') aan een modelattribuut, en validatie schrijf je als method chain op dat veld.
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
class CustomerForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Section::make('Klantgegevens')
->schema([
TextInput::make('name')
->required()
->maxLength(255),
TextInput::make('email')
->email()
->unique(ignoreRecord: true),
Select::make('account_manager_id')
->relationship('accountManager', 'name')
->searchable(),
Toggle::make('is_active')
->default(true),
]),
]);
}
}
Wat hier gebeurt:
required(),maxLength(),email()enunique()worden Laravel-validatieregels. Je schrijft ze niet dubbel.unique(ignoreRecord: true)negeert het huidige record bij bewerken. Anders faalt de validatie op het eigen e-mailadres.relationship()op eenSelectvult de opties uit de gerelateerde tabel en slaat de foreign key op.
Filament heeft standaard velden voor vrijwel elk scenario: text input, select, checkbox, toggle, radio, date-time picker, file upload, rich editor, markdown editor, repeater, builder, tags input, textarea, key-value, color picker, slider en code editor. Mist er iets? Dan bouw je een eigen veld. Hoe dat werkt, lees je in custom velden en componenten in Filament.
Hoe werkt een Filament table?
Een Filament table is de lijstweergave van een resource. Je definieert kolommen, filters, record actions per rij en toolbar actions voor bulkbewerkingen.
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
class CustomersTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable()
->sortable(),
TextColumn::make('accountManager.name')
->label('Accountmanager'),
IconColumn::make('is_active')
->boolean(),
TextColumn::make('created_at')
->dateTime()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
SelectFilter::make('account_manager_id')
->relationship('accountManager', 'name'),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
De kern:
searchable()voegt de kolom toe aan de zoekbalk.sortable()maakt de kolomkop klikbaar.- Dot notation (
accountManager.name) haalt data uit een relatie. toggleable()laat gebruikers zelf kolommen tonen of verbergen.recordActions()entoolbarActions()zijn de v4-namen. In v3 heetten zeactions()enbulkActions().
Let op: elke searchable()-kolom wordt een LIKE-query. Op een tabel met honderdduizenden rijen en een relatiekolom voel je dat. Filament claimt dat tables in v4 tot 3x sneller renderen, maar je database-indexen blijven jouw verantwoordelijkheid. Daarover meer in Filament performance bij grote datasets.
Wat is een infolist en wanneer gebruik je die?
Een infolist toont recorddata read-only. Je gebruikt hem op een View-pagina, in relation managers en in action modals, wanneer bewerken niet de bedoeling is.
Genereer de resource met --view en Filament maakt een CustomerInfolist.php in de Schemas-map. De opbouw lijkt sterk op een form:
use Filament\Infolists\Components\IconEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Schema;
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextEntry::make('name'),
TextEntry::make('email'),
TextEntry::make('accountManager.name'),
IconEntry::make('is_active')->boolean(),
]);
}
Beschikbare entries: text, icon, image, color, code, key-value en repeatable entry. In de praktijk zien wij dat infolists vaak worden overgeslagen. Dat is zonde. Een supportmedewerker die alleen moet kijken, hoort niet in een bewerkformulier te zitten. Combineer de View-pagina met rechten via policies en je voorkomt per ongeluk gewijzigde data. Zie ook rollen en rechten met Filament Shield.
Wat zijn Filament actions?
Een action is een knop die iets doet: openen, bevestigen, een modal met formulier tonen of code uitvoeren. Sinds v4 zitten alle actions in één namespace, Filament\Actions, en werken ze overal hetzelfde.
In v3 had je aparte klassen voor table actions, page actions en form actions. Die zijn samengevoegd. Een EditAction in een table is dezelfde klasse als in een page header.
Een eigen action met modal-formulier:
use Filament\Actions\Action;
use Filament\Forms\Components\Textarea;
use Illuminate\Database\Eloquent\Model;
Action::make('blokkeren')
->requiresConfirmation()
->color('danger')
->schema([
Textarea::make('reden')->required(),
])
->action(function (array $data, Model $record): void {
$record->update([
'is_active' => false,
'blocked_reason' => $data['reden'],
]);
})
Filament levert kant-en-klare actions voor de standaard Eloquent-operaties:
| Action | Wat het doet | Typische plek |
|---|---|---|
CreateAction | Nieuw record aanmaken | Page header, relation manager |
EditAction | Record bewerken | Table-rij |
ViewAction | Record bekijken (infolist) | Table-rij |
DeleteAction | Record verwijderen | Table-rij, edit page |
ReplicateAction | Record dupliceren | Table-rij |
RestoreAction / ForceDeleteAction | Soft deletes beheren | Table-rij |
ImportAction / ExportAction | CSV in- en uitvoer | Page header, toolbar |
Import en export zijn een eigen onderwerp. Zie Filament import en export van CSV.
Hoe beheer je relaties met relation managers?
Een relation manager is een interactieve table onder je edit- of view-pagina die gerelateerde records toont. Je kunt daar records aanmaken, bewerken, koppelen en ontkoppelen zonder de pagina te verlaten.
Genereer er een met de resource, de relatienaam en de titelkolom:
php artisan make:filament-relation-manager CustomerResource orders number
Het resultaat is een klasse met een eigen form() en table():
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\TextInput;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class OrdersRelationManager extends RelationManager
{
protected static string $relationship = 'orders';
public function form(Schema $schema): Schema
{
return $schema->components([
TextInput::make('number')->required(),
]);
}
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('number'),
])
->headerActions([
CreateAction::make(),
])
->recordActions([
EditAction::make(),
DeleteAction::make(),
]);
}
}
Registreer hem in de resource:
public static function getRelations(): array
{
return [
RelationManagers\OrdersRelationManager::class,
];
}
Let op het verschil: in een relation manager zijn form() en table() niet static. In een resource wel.
Bij many-to-many-relaties gebruik je AttachAction en DetachAction. Bij one-to-many waar het record al bestaat, gebruik je AssociateAction en DissociateAction.
Welke bouwsteen kies je voor welke relatie?
Niet elke relatie verdient een relation manager. Filament biedt vier manieren, en de juiste keuze hangt af van het relatietype en hoe vaak gebruikers de data aanpassen.
| Situatie | Relatietype | Beste keuze |
|---|---|---|
| Eén gerelateerd record kiezen | BelongsTo, BelongsToMany | Select met relationship() |
| Paar child-records inline bewerken | HasMany, MorphMany | Repeater met relationship() |
| Veel child-records met zoeken en filteren | HasMany, BelongsToMany | Relation manager |
| Relatiedata op eigen pagina met sub-navigatie | Alle | Relation page (ManageRelatedRecords) |
| Eén-op-één-gegevens in het hoofdformulier | HasOne, BelongsTo | Layout-component met relationship() |
De vuistregel die wij hanteren: komen er meer dan een handvol child-records, of moet iemand erin zoeken? Dan een relation manager. Een repeater met vijftig orderregels laadt alles in één Livewire-component, en dat merk je.
Hoe passen deze bouwstenen samen?
Een resource is het frame, en de andere vijf bouwstenen vullen het in. Zo verdeelt Filament het werk:
| Bouwsteen | Klasse / namespace | Doel | Pagina |
|---|---|---|---|
| Resource | Filament\Resources\Resource | Model koppelen, pagina's en relaties registreren | Alle |
| Schema | Filament\Schemas\Schema | Container voor velden, entries en layout | Create, Edit, View |
| Form | Filament\Forms\Components\ | Invoer en validatie | Create, Edit |
| Table | Filament\Tables\Table | Lijst, zoeken, filteren, sorteren | List |
| Infolist | Filament\Infolists\Components\ | Read-only weergave | View |
| Action | Filament\Actions\* | Knoppen, modals, bulkbewerkingen | Overal |
| Relation manager | Filament\Resources\RelationManagers\RelationManager | Gerelateerde records beheren | Edit, View |
Wie de losse onderdelen begrijpt, kan ze ook buiten een panel gebruiken. Tables, schemas, forms, infolists en actions zijn aparte packages. Je kunt een Filament table dus in een eigen Livewire-component plaatsen, bijvoorbeeld in een klantportaal waar je geen volledige admin-omgeving wilt.
De eerlijke versie: waar Filament wringt
Filament is snel zolang je binnen de conventies blijft. Daarbuiten kost het meer tijd dan je verwacht.
- Complexe formulieren met veel afhankelijkheden. Velden die live op elkaar reageren, betekenen Livewire-roundtrips. Bij tientallen reactieve velden wordt dat traag.
- Zeer afwijkende UI. Een configurator of planbord bouw je beter als eigen Livewire- of Vue-component.
- Upgrades van v3. De namespace-wijzigingen raken vrijwel elk bestand. Er is een upgrade-script, maar handwerk blijft nodig.
Voor de meeste backoffices, interne tools en Laravel-dashboards wegen die punten niet op tegen de snelheid. Een resource met form, table en filters staat er in een uur. Het stappenplan voor een compleet panel lees je in een Filament admin panel bouwen.
Samengevat
- Een resource koppelt een Eloquent-model aan list-, create-, edit- en view-pagina's.
- Schemas zijn sinds v4 de gedeelde basis voor forms en infolists. Layout-componenten staan in
Filament\Schemas\Components. - Een form gebruikt velden uit
Filament\Forms\Componentsmet validatie als method chain. - Een table heeft
columns(),filters(),recordActions()entoolbarActions(). - Een infolist toont data read-only op de View-pagina.
- Actions zitten allemaal in
Filament\Actionsen werken in tables, schemas en page headers. - Relation managers zijn tables voor gerelateerde records. Voor kleine relaties volstaat een
SelectofRepeater. - v5 heeft dezelfde API als v4. Code uit dit artikel werkt in beide.
Veelgestelde vragen
Wat is het verschil tussen een Filament form en een infolist?
Een form is voor invoer en validatie, een infolist toont data alleen. Beide zijn sinds v4 een Schema, dus de opbouw is bijna gelijk. Je gebruikt een form op create- en edit-pagina's en een infolist op de view-pagina.
Werkt code voor Filament 4 ook in Filament 5?
Ja. Filament 5 bracht geen nieuwe features en houdt dezelfde API als v4. Het verschil zit in de ondersteuning voor Livewire 4. Code die je voor v4 schreef, draait in v5 zonder aanpassingen aan resources, forms of tables.
Hoe maak ik snel een Filament resource met alle velden?
Gebruik php artisan make:filament-resource Model --generate. Filament leest dan je databasekolommen en vult form en table automatisch. Je houdt een startpunt over dat je daarna verfijnt met labels, validatie en filters.
Waarom heten de table actions anders dan in v3?
In v4 zijn alle actions samengevoegd in Filament\Actions. Daarom heten de table-methodes nu recordActions() en toolbarActions() in plaats van actions() en bulkActions(). Bulk actions zet je in een BulkActionGroup binnen toolbarActions().
Wanneer kies ik een relation manager boven een repeater?
Kies een relation manager zodra er veel gerelateerde records zijn of gebruikers moeten zoeken en filteren. Een repeater past bij een klein aantal child-records die je samen met het hoofdrecord opslaat. Grote repeaters maken het formulier traag.
Kan ik Filament tables gebruiken zonder admin panel?
Ja. Tables, forms, schemas, infolists en actions zijn losse packages. Je plaatst ze in je eigen Livewire-componenten, bijvoorbeeld in een klantportaal of een intern dashboard buiten het panel.
Twijfel je of Filament past bij jouw backoffice of Laravel-maatwerk? Neem contact op, dan kijken we er samen naar.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →