Laravel Filament ile Admin Paneli: Temel Kavramlar ve İlk Kaynak
Filament, Laravel ekosisteminde admin paneli, form ve tablo arayüzlerini hızlıca üretmek için kullanılan bir araç setidir. Temelinde Livewire ve Alpine.js bulunur; yani Filament sayfaları aslında birer Livewire bileşenidir. Bu rehber, orta seviye bir Laravel geliştiricisinin Filament'in panel, kaynak (resource), form ve tablo katmanlarını nasıl bir araya getirdiğini adım adım ele alır.
Sürüm kapsamı: Filament'in 3.x serisi hedeflenmiştir. Sürüm numaraları hızlı değiştiği için burada belirli bir yama sürümüne bağlı kalınmamıştır; kurulum komutlarını çalıştırdığınızda Composer, ilgili ana sürümün güncel yamasını çeker. Filament'in API'si ana sürümler arasında belirgin biçimde değişebildiğinden, yükseltme yapmadan önce resmi yükseltme notlarına bakmanız gerekir.
Önkoşullar
- PHP 8.1 veya üzeri
- Laravel 10 veya üzeri bir uygulama
- Çalışan bir veritabanı bağlantısı
- Composer ve npm (Filament kendi asset'lerini yayınlar; tema özelleştirmesi yapacaksanız npm gerekir)
Filament panelini kurmadan önce uygulamanızın APP_URL değerinin doğru olduğundan emin olun. Yanlış APP_URL, panel asset'lerinin ve yönlendirmelerin bozuk görünmesine yol açar.
Kurulum
Filament'i paket olarak ekleyip panel oluşturucuyu çalıştırın:
composer require filament/filament:"^3.0"
php artisan filament:install --panels
filament:install --panels komutu, bir panel oluşturur ve gerekli yapılandırmayı üretir. Panel, varsayılan olarak /admin yolunda yayınlanır. Bu komut ayrıca bir PanelProvider sınıfı oluşturur; panelin davranışını bu sınıftan yönetirsiniz.
Kurulumdan sonra, panele erişebilmek için bir kullanıcıyı panel kullanıcısı yapmanız gerekir. Filament, FilamentUser arayüzünü uygulayan modelleri panel kullanıcısı olarak kabul eder:
<?php
namespace App\Models;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser
{
public function canAccessPanel(Panel $panel): bool
{
return $this->is_admin === true;
}
}
canAccessPanel metodunun dönüş değeri, kullanıcının ilgili panele erişip erişemeyeceğini belirler. Burada bir is_admin alanına bağlı örnek verilmiştir; kendi yetkilendirme modelinize göre uyarlamanız beklenir. Bu metodu boş bırakıp herkese true döndürmek, üretim ortamında panelin kimlik doğrulaması olmayan herkese açık kalması anlamına gelir. Bu, en sık yapılan ve en ciddi güvenlik hatasıdır.
İlk Resource: Model ile Tablo ve Formu Bağlamak
Filament'te "resource", bir Eloquent modeli etrafında liste, oluşturma, düzenleme ve silme ekranlarını üreten sınıftır. Örnek olarak basit bir Post modeli üzerinden ilerleyelim:
php artisan make:filament-resource Post
Bu komut app/Filament/Resources/PostResource.php dosyasını ve ilgili sayfa sınıflarını üretir. İçeriği sadeleştirilmiş hali şöyledir:
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\PostResource\Pages;
use App\Models\Post;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class PostResource extends Resource
{
protected static ?string $model = Post::class;
public static function form(Form $form): Form
{
return $form->schema([
Forms\Components\TextInput::make('title')
->required()
->maxLength(255),
Forms\Components\Textarea::make('body')
->required()
->columnSpanFull(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable(),
])
->defaultSort('created_at', 'desc');
}
public static function getPages(): array
{
return [
'index' => Pages\ListPosts::route('/'),
'create' => Pages\CreatePost::route('/create'),
'edit' => Pages\EditPost::route('/{record}/edit'),
];
}
}
Buradaki üç metot, resource'un üç temel katmanını temsil eder:
form: Oluşturma ve düzenleme ekranlarındaki alanları tanımlar.table: Liste ekranındaki sütunları, aramayı ve sıralamayı tanımlar.getPages: Resource'un hangi rotalara karşılık geldiğini belirler.
TextInput::make('title') gibi alanlar, model özellik adlarıyla eşleşir. columnSpanFull() gibi zincir metotları, alanın grid içindeki yerleşimini kontrol eder.
Form Alanları ve Doğrulama
Filament form bileşenleri, Laravel'in doğrulama kurallarını zincir metotlarla ifade etmenizi sağlar. required, maxLength, unique, email gibi kurallar doğrudan alan tanımına eklenir:
Forms\Components\TextInput::make('slug')
->required()
->maxLength(255)
->unique(ignoreRecord: true),
Forms\Components\Select::make('status')
->options([
'draft' => 'Taslak',
'published' => 'Yayında',
])
->required(),
Forms\Components\DateTimePicker::make('published_at')
->label('Yayın Tarihi'),
unique(ignoreRecord: true) ifadesi, düzenleme ekranında kaydın kendi değerinin "çakışan kayıt" olarak görülmemesini sağlar. Bu bayrağı eklemeyi unutmak, bir kaydı başka bir alanını değiştirirken bile "bu değer zaten kullanılıyor" hatası almanıza neden olur.
İlişkili modeller için Select bileşenine relationship() eklenebilir:
Forms\Components\Select::make('category_id')
->relationship('category', 'name')
->searchable()
->preload(),
relationship('category', 'name'), Post modelindeki category ilişkisini kullanır ve seçenekleri categories tablosundaki name alanından üretir. İlişki metodu modelde tanımlı değilse bu alan hata verir; form alanını eklemeden önce ilişkiyi modelde tanımlamış olmanız gerekir.
Tablo Sütunları, Filtreler ve İşlemler
Liste ekranını üretken kılan kısım tablo tanımıdır. Sütunlara arama ve sıralama eklemek tek satırlık işlerdir:
Tables\Columns\TextColumn::make('status')
->badge()
->color(fn (string $state): string => match ($state) {
'draft' => 'gray',
'published' => 'success',
default => 'gray',
}),
Tables\Columns\IconColumn::make('is_featured')
->boolean(),
Filtreler, tabloya ek bir katman olarak eklenir:
->filters([
Tables\Filters\SelectFilter::make('status')
->options([
'draft' => 'Taslak',
'published' => 'Yayında',
]),
Tables\Filters\TrashedFilter::make(),
])
TrashedFilter, modelde soft delete kullanılıyorsa silinmiş kayıtları görüntülemeyi sağlar; soft delete tanımlı değilse bu filtre anlamlı çalışmaz.
Satır işlemleri (actions) ve toplu işlemler (bulkActions) tablonun davranış katmanıdır:
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
DeleteAction ve DeleteBulkAction, model üzerinde silme işlemini tetikler. Modelde soft delete varsa kayıt kalıcı olarak silinmez; bu davranışı bilmeden "silme çalışmıyor" sonucuna varmak yaygın bir yanılgıdır.
Yetkilendirme ve Politikalarla Sınırlama
Filament, Laravel'in policy yapısıyla doğal biçimde entegre olur. Bir model için policy tanımladığınızda, resource ekranlarındaki görüntüleme, oluşturma, güncelleme ve silme işlemleri bu politikalara göre sınırlanır. Örneğin PostPolicy içindeki viewAny, create, update ve delete metotları, ilgili ekranların ve işlem butonlarının görünürlüğünü etkiler.
Bu, iki katmanlı bir güvenlik yaklaşımı gerektirir:
canAccessPanel: Panele kimlerin girebileceğini belirler.- Policy'ler: Panele girmiş bir kullanıcının hangi kayıtlar üzerinde hangi işlemleri yapabileceğini belirler.
Yalnızca canAccessPanel ile koruma sağlamak yetersizdir; panel içindeki tüm kullanıcıların tüm kayıtları yönetebildiği bir sistem, yetki ayrımı olmayan bir sistemdir. Policy'leri tanımlamak, özellikle birden fazla rolün bulunduğu uygulamalarda zorunludur.
Yaygın Hatalar
- Panel erişimini herkese açık bırakmak:
canAccessPanelmetodunun koşulsuztruedöndürmesi, üretimde panelin korumasız kalmasına yol açar. uniquedoğrulamasındaignoreRecordkullanmamak: Düzenleme ekranında kendi değerini çakışma olarak gören form, kaydın güncellenmesini engeller.- İlişki alanını model tanımı olmadan eklemek:
relationship()çağrısı, modelde karşılığı olmayan bir ilişki adı verildiğinde hata üretir. - Soft delete farkındalığı olmadan silme davranışını yorumlamak: Silme işlemi kaydı kalıcı silmiyorsa, bu bir hata değil, model yapılandırmasının sonucudur.
- Asset derleme adımını atlamak: Tema özelleştirmesi yaptıysanız ve
npm run buildçalıştırmadıysanız, panelde eski stiller görünmeye devam eder.
Performans ve Ölçeklenme Notları
Filament tabloları, ilişkili sütunları gösterirken her satır için ek sorgu üretebilir. İlişkili bir sütun tanımladığınızda, resource'un sorgusuna modifyQueryUsing ile eager loading eklemek, N+1 sorgu problemini önler:
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('category.name'),
])
->modifyQueryUsing(fn ($query) => $query->with('category'));
}
Bu, özellikle yüzlerce satırın listelendiği ekranlarda belirgin fark yaratır. Sütun sayısı ve ilişki derinliği arttıkça, sorguyu özelleştirmek kaçınılmaz hale gelir.
Sonuç
Filament, Laravel uygulamalarında admin panelini sıfırdan yazmak yerine, form ve tablo tanımlarını bildirimsel biçimde ifade etmenizi sağlar. Resource, form ve tablo katmanlarını ayırmak; doğrulama ve yetkilendirmeyi Laravel'in kendi mekanizmalarına (validation kuralları, policy'ler) bırakmak, hem bakımı kolay hem de güvenli bir panel ortaya çıkarır. Kurulum ve temel resource akışını oturttuktan sonra, panelin gerçek ihtiyaçlarına göre filtre, işlem ve ilişki katmanlarını kademeli olarak eklemek, tek seferde karmaşık bir yapı kurmaktan daha yönetilebilir bir yol izler.