Gereksinimler ve Ön Hazırlık
Uygulamayı geliştirmeye başlamadan önce sisteminizde Laravel 11 veya üzeri bir sürümün yüklü olduğundan emin olun. Ayrıca veritabanı yönetimi için MySQL veya PostgreSQL kullanmanız önerilir. Projenizin temel kurulumlarını tamamladıktan sonra aşağıdaki adımları izleyebilirsiniz.
- PHP 8.2+ sürümü.
- Laravel 11.x framework kurulumu.
- Composer paket yöneticisi.
- Temel düzeyde SQL ve Eloquent bilgisi.
Adım 1: Veritabanı Şemasını ve İlişkileri Kurgulama
Favori sistemi, "Çoka-Çok" (Many-to-Many) ilişkisine dayanan bir yapıdır. Bir kullanıcı birden fazla ürünü favorileyebilir, bir ürün de birden fazla kullanıcı tarafından favorilere eklenebilir. Bu ilişkiyi yönetmek için bir ara tabloya (pivot table) ihtiyacımız vardır.
php artisan make:migration create_favorites_table
Oluşturulan migration dosyasını şu şekilde düzenleyerek veritabanı yapısını tanımlayın:
public function up(): void
{
Schema::create('favorites', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('product_id')->constrained()->onDelete('cascade');
$table->timestamps();
// Aynı ürünün iki kez favorilenmesini engellemek için benzersiz kısıtlama
$table->unique(['user_id', 'product_id']);
});
}
Burada onDelete('cascade') kullanarak, kullanıcı silindiğinde veya ürün kaldırıldığında favori kayıtlarının otomatik olarak temizlenmesini sağlıyoruz. unique kısıtlaması ise veri bütünlüğünü korumak adına kritik bir güvenlik önlemidir.
Adım 2: Eloquent Modellerini Yapılandırma
Veritabanı ilişkilerini Laravel tarafında tanımlamak için User ve Product modellerini güncellememiz gerekir. Bu, favori listesine erişimi oldukça kolaylaştıracaktır.
// User.php Modeli
public function favorites(): BelongsToMany
{
return $this->belongsToMany(Product::class, 'favorites')->withTimestamps();
}
Bu ilişki tanımlaması sayesinde $user->favorites diyerek kullanıcının tüm favori ürünlerini bir koleksiyon olarak çekebiliriz. Aynı işlemi Product modeli için de yapmalıyız.
// Product.php Modeli
public function favoritedBy(): BelongsToMany
{
return $this->belongsToMany(User::class, 'favorites')->withTimestamps();
}
Adım 3: Favori İşlemleri İçin Controller Oluşturma
Favoriye ekleme ve çıkarma işlemlerini yönetecek bir FavoriteController oluşturmalıyız. Bu controller, kullanıcının isteğini işleyecek ve ilgili veritabanı sorgularını çalıştıracaktır.
public function toggle(Product $product, Request $request)
{
$user = $request->user();
// Eğer favorilerde varsa kaldır, yoksa ekle
$user->favorites()->toggle($product->id);
return back()->with('success', 'İşlem başarıyla gerçekleşti.');
}
toggle metodu, Laravel'in sunduğu çok güçlü bir yöntemdir. Eğer kayıt veritabanında mevcutsa siler, mevcut değilse ekler. Bu sayede ayrı ayrı "ekle" ve "sil" fonksiyonları yazmanıza gerek kalmaz.
Adım 4: Güvenli Rota Tanımlamaları
Rotalarımızı tanımlarken kullanıcı kimlik doğrulamasını (authentication) zorunlu tutmalıyız. Aksi takdirde giriş yapmamış kullanıcılar favori işlemi yapamaz.
use App\Http\Controllers\FavoriteController;
Route::middleware('auth')->group(function () {
Route::post('/favorites/{product}/toggle', [FavoriteController::class, 'toggle'])
->name('favorites.toggle');
});
Kritik Güvenlik Uyarısı: Rotalarınızda mutlakaauthmiddleware'ini kullanın. Ayrıca, form isteklerinde@csrfdirektifini kullanmayı unutmayın; aksi takdirde uygulamanız CSRF (Siteler Arası İstek Sahteciliği) saldırılarına açık hale gelir.
Adım 5: Blade Şablonunda Favori Butonu
Kullanıcı arayüzünde favori durumunu göstermek için contains metodunu kullanabiliriz. Bu, veritabanında sorgu çalıştırmadan koleksiyon üzerinde kontrol sağlar.
@csrf
{{ auth()->user()->favorites->contains($product->id) ? 'Favorilerden Çıkar' : 'Favorilere Ekle' }}
Bu kod bloğu, kullanıcının o anki ürünü favorileyip favorilemediğini kontrol eder ve butonu buna göre dinamik olarak günceller.
Yöntem Karşılaştırması
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Eloquent Toggle | Hızlı, temiz ve okunabilir. | Büyük verilerde performans takibi gerektirir. |
| Manual Sync | Daha fazla kontrol sağlar. | Kod karmaşıklığını artırır. |
Sıkça Sorulan Sorular
Favori listesini nasıl performanslı çekerim?
Kullanıcının favorilerini çekerken $user->favorites()->paginate(10) kullanarak veritabanı yükünü hafifletebilir ve sayfalama yapabilirsiniz.
Aynı ürünün birden fazla favorilenmesini nasıl önlerim?
Migration dosyasında $table->unique(['user_id', 'product_id']) kullanarak veritabanı seviyesinde kısıtlama yapmak en güvenli yoldur.
Favori sayısı nasıl gösterilir?
Product modeline $product->favoritedBy()->count() metodunu ekleyerek ürünün kaç kişi tarafından favorilendiğini kolayca gösterebilirsiniz.
Giriş yapmamış kullanıcılar için ne yapmalıyım?
Giriş yapmamış kullanıcılar için butonu devre dışı bırakabilir veya onları giriş sayfasına yönlendiren bir uyarı gösterebilirsiniz.
Favori silme işleminde özel bir mesaj döndürebilir miyim?
Evet, toggle metodundan dönen sonucu kontrol ederek session()->flash() ile kullanıcıya özel mesajlar gösterebilirsiniz.
Sorumluluk Reddi: Bu rehberdeki kod örnekleri genel eğitim amaçlıdır. Üretim ortamında (production) veritabanı indekslemelerini ve sunucu önbellekleme (caching) mekanizmalarını yapılandırmayı ihmal etmeyin.
Favori Listeleme Sisteminde İleri Düzey Optimizasyon ve Önbellekleme
Sisteminiz büyüdükçe ve kullanıcı sayınız arttıkça, her favori sorgusunda veritabanına gitmek uygulama performansını olumsuz etkileyebilir. Özellikle "popüler ürünler" veya "en çok favorilenenler" gibi listelemelerde Laravel'in Cache mekanizmasını kullanmak kritik bir öneme sahiptir.
Favori listesini önbelleğe alırken, kullanıcının favori listesi değiştiğinde (ekleme veya silme yapıldığında) önbelleği temizlemeyi (flush) unutmamalısınız. İşte basit bir önbellek stratejisi örneği:
use Illuminate\Support\Facades\Cache;
public function index()
{
$userId = auth()->id();
// Kullanıcıya özel favorileri 60 dakika önbellekte tut
return Cache::remember("user_favorites_{$userId}", 3600, function () {
return auth()->user()->favorites()->get();
});
}
// Favori eklendiğinde önbelleği temizle
public function store(Request $request)
{
// ... favori ekleme mantığı
Cache::forget("user_favorites_" . auth()->id());
}
Favori Sistemini Test Etme ve Hata Ayıklama
Yazdığınız favori sisteminin kararlılığını sağlamak için PHPUnit kullanarak birim testleri (unit tests) yazmanız önerilir. Özellikle bir kullanıcının aynı ürünü iki kez favorileyememesi veya giriş yapmamış bir kullanıcının favori ekleyememesi gibi senaryoları test etmek, uygulamanızın güvenliğini artırır.
Aşağıdaki test örneği, favori ekleme sürecinin doğruluğunu kontrol eder:
public function test_user_can_favorite_a_product()
{
$user = User::factory()->create();
$product = Product::factory()->create();
$this->actingAs($user)
->post(route('favorites.store', $product->id))
->assertStatus(200);
$this->assertDatabaseHas('favorites', [
'user_id' => $user->id,
'product_id' => $product->id,
]);
}
Hata ayıklama sürecinde ise Laravel Telescope kullanarak favori işlemlerinin veritabanına gönderdiği sorguları anlık olarak izleyebilir, gereksiz sorgu (N+1 problemi) oluşup oluşmadığını kolayca tespit edebilirsiniz. Eğer veritabanı sorgularınızda yavaşlama hissediyorsanız, favorites tablonuzdaki user_id ve product_id sütunlarına composite index eklediğinizden emin olun:
// Migration dosyanızda:
$table->unique(['user_id', 'product_id']);
$table->index('user_id');
Bu indeksleme, veritabanı motorunun favori listelerini çok daha hızlı taramasını sağlayarak, özellikle binlerce favori kaydının olduğu tablolarda sorgu süresini milisaniyelere indirecektir.
Sonuç
Laravel ile dinamik bir favori listeleme sistemi oluşturmak, Eloquent ORM'in sunduğu ilişkisel yetenekler sayesinde oldukça verimli bir süreçtir. Bu rehberde, veritabanı modellemesinden başlayarak, controller mantığı ve Blade şablon entegrasyonuna kadar uçtan uca bir sistem kurduk. Bir sonraki adım olarak, bu favori listesini AJAX (JavaScript) ile sayfa yenilenmeden güncellenecek şekilde optimize edebilirsiniz.


Yorumlar (0)
Yorum Yaz