Gereksinimler ve Ön Hazırlık
Bu projeye başlamadan önce bilgisayarınızda PHP 8.2+ sürümünün, Composer paket yöneticisinin ve Laravel 11 veya üzeri bir sürümün yüklü olduğundan emin olun. Veritabanı yönetim sistemi olarak MySQL veya PostgreSQL kullanmanız önerilir.
- Laravel 11.x yüklü bir proje dizini.
- Veritabanı bağlantı ayarlarının .env dosyasında yapılandırılmış olması.
- Temel düzeyde Eloquent ORM bilgisi.
Takip Sistemi İçin Veritabanı Yapılandırması
Takip sistemi, "self-referencing many-to-many" (kendi kendine referans veren çoktan çoğa) ilişki yapısını kullanır. Bir kullanıcı hem takip eden hem de takip edilen olabilir. Bu ilişkiyi yönetmek için 'follows' adında bir ara tablo oluşturacağız.
php artisan make:migration create_follows_table
Oluşturulan migration dosyasını aşağıdaki şekilde güncelleyerek takip eden (follower) ve takip edilen (following) sütunlarını tanımlayın.
public function up(): void
{
Schema::create('follows', function (Blueprint $table) {
$table->id();
$table->foreignId('follower_id')->constrained('users')->onDelete('cascade');
$table->foreignId('following_id')->constrained('users')->onDelete('cascade');
$table->timestamps();
});
}
Bu yapı, `follower_id` ve `following_id` sütunlarını `users` tablosuna bağlar. `onDelete('cascade')` kuralı, bir kullanıcı silindiğinde ona ait tüm takip ilişkilerinin de otomatik olarak temizlenmesini sağlar.
User Modelinde İlişkilerin Tanımlanması
Eloquent ORM üzerinde bu ilişkileri kurmak, verileri sorgularken büyük kolaylık sağlar. `User.php` modeline takip edenleri ve takip edilenleri getirecek metodları ekleyelim.
public function followings()
{
return $this->belongsToMany(User::class, 'follows', 'follower_id', 'following_id')
->withTimestamps();
}
public function followers()
{
return $this->belongsToMany(User::class, 'follows', 'following_id', 'follower_id')
->withTimestamps();
}
Bu metodlar, Laravel'in `belongsToMany` ilişkisini kullanarak iki kullanıcı arasındaki bağlantıyı dinamik olarak yönetmemizi sağlar. `withTimestamps()` metodu, ilişkinin ne zaman kurulduğunu takip etmemize olanak tanır.
Arkadaşlık Sistemi: İstek ve Onay Mekanizması
Arkadaşlık sistemi, takip sisteminden farklı olarak bir "durum" (status) bilgisi gerektirir. İstek gönderildi, onaylandı veya reddedildi gibi durumları yönetmek için `friendships` tablosuna bir `status` sütunu eklememiz gerekir.
public function up(): void
{
Schema::create('friendships', function (Blueprint $table) {
$table->id();
$table->foreignId('sender_id')->constrained('users');
$table->foreignId('recipient_id')->constrained('users');
$table->enum('status', ['pending', 'accepted', 'rejected'])->default('pending');
$table->timestamps();
});
}
Burada `enum` kullanımı, veritabanı seviyesinde veri bütünlüğünü sağlar. Sadece belirtilen üç durumun girilmesine izin verilir.
İlişki Yönetimi Karşılaştırma Tablosu
| Özellik | Takip Sistemi | Arkadaşlık Sistemi |
|---|---|---|
| Onay Mekanizması | Yok (Doğrudan) | Var (İstek/Onay) |
| İlişki Türü | Tek Yönlü | Çift Yönlü |
| Veritabanı Tablosu | Basit Ara Tablo | Durum Sütunlu Ara Tablo |
Kontrolcü (Controller) ile İş Mantığını Yönetme
Kullanıcıların birbirini takip etmesi veya arkadaşlık isteği göndermesi için bir `SocialController` oluşturmalısınız. İşte bir kullanıcıyı takip etme mantığı:
public function follow(User $user)
{
auth()->user()->followings()->attach($user->id);
return back()->with('success', 'Kullanıcı takip edildi.');
}
Bu kod bloğu, `attach` metodunu kullanarak `follows` tablosuna yeni bir kayıt ekler. Güvenlik için, bu metodun `auth` middleware'i ile korunması şarttır.
Güvenlik Uyarısı: Kullanıcı girişleri her zaman doğrulanmalıdır. `attach` veya `sync` gibi metodları kullanırken, kullanıcının kendi kendini takip etmesini engelleyen bir kontrol (if/else) eklemeyi unutmayın.
Sıkça Sorulan Sorular
Takip edilenler listesini nasıl optimize edebilirim?
Büyük veri setlerinde `with('followings')` kullanarak "Eager Loading" (istekli yükleme) yapmanız, N+1 sorgu sorununu engelleyerek performansı ciddi oranda artırır.
Arkadaşlık isteğini nasıl reddedebiliriz?
`friendships` tablosundaki `status` sütununu `rejected` olarak güncelleyebilir veya ilgili kaydı veritabanından tamamen silebilirsiniz.
Kullanıcının arkadaşlık isteği gönderip göndermediğini nasıl anlarım?
Bir `Friendship` modeli oluşturup `where('sender_id', $id)->where('recipient_id', $targetId)->exists()` sorgusu ile isteğin varlığını kontrol edebilirsiniz.
Takip sisteminde bildirimleri nasıl tetiklerim?
Laravel'in yerleşik `Notification` sistemini kullanarak, takip işlemi gerçekleştiğinde `DatabaseNotification` aracılığıyla kullanıcıya bildirim gönderebilirsiniz.
Veritabanı indeksleri gerekli midir?
Evet, `follower_id` ve `following_id` sütunlarına mutlaka indeks eklemelisiniz. Bu, arama sorgularının hızını binlerce kat artıracaktır.
Sorumluluk Reddi: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) veritabanı işlemlerinde mutlaka transaction (işlem yönetimi) kullanın ve kullanıcı girdilerini her zaman Validate (doğrula) edin.
Performans Optimizasyonu: N+1 Sorgu Problemini Çözme
Sosyal ağ projelerinde en sık karşılaşılan performans darboğazı, kullanıcı listelerini çekerken oluşan N+1 sorgu problemidir. Örneğin, takip edilen 50 kişinin profil bilgilerini tek bir sayfada listelerken, her kullanıcı için ayrı bir veritabanı sorgusu tetiklemek sisteminizi yavaşlatır. Bunu Eloquent'in with() metodu ile "Eager Loading" kullanarak kolayca çözebilirsiniz.
// Controller içerisinde takip edilenleri optimize edilmiş şekilde çekme
public function followingList(User $user)
{
$following = $user->following()->with('profile')->paginate(20);
return view('profile.following', compact('following'));
}
Bu yöntem, Laravel'in ilişkili verileri tek bir sorguda (WHERE IN (...) mantığıyla) çekmesini sağlar. Ayrıca, çok büyük takipçi sayılarına sahip popüler hesaplar için count() sorgularını doğrudan veritabanı üzerinde yapmak yerine, withCount() metodunu kullanarak veritabanı yükünü minimize etmelisiniz.
Sistem Testleri: İlişkilerin Doğruluğunu Sağlama
Arkadaşlık ve takip sistemleri kritik veriler içerdiği için, bu yapıların test edilmesi hata payını sıfıra indirir. Laravel'in yerleşik PHPUnit desteği ile bir kullanıcının diğerini takip edip edemediğini veya mükerrer kayıtların oluşup oluşmadığını test edebilirsiniz.
public function test_user_can_follow_another_user()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$response = $this->actingAs($user1)
->post(route('follow', $user2->id));
$response->assertStatus(200);
$this->assertDatabaseHas('follows', [
'follower_id' => $user1->id,
'following_id' => $user2->id,
]);
}
Test süreçlerinde DatabaseTransactions trait'ini kullanarak her testten sonra veritabanının temizlenmesini sağlayabilir, böylece test ortamınızın her zaman izole kalmasını garanti altına alabilirsiniz.
İleri İpuçları: İlişki Durumunu Önbelleğe Alma (Caching)
Sisteminize binlerce kullanıcı dahil olduğunda, "Bu kullanıcıyı takip ediyor muyum?" kontrolü için her sayfa yüklenişinde veritabanına gitmek maliyetli olabilir. Bu tür sık sorgulanan verileri Cache katmanında tutmak, uygulamanızın yanıt süresini milisaniyelere indirir.
public function isFollowing($userId)
{
return Cache::remember("user_{$this->id}_follows_{$userId}", 3600, function () use ($userId) {
return $this->following()->where('following_id', $userId)->exists();
});
}
Not: Önbellek kullanırken, takip işlemi gerçekleştiğinde veya iptal edildiğinde ilgili önbellek anahtarını (cache key) forget() metodu ile temizlemeyi unutmayın. Aksi takdirde kullanıcı takip etse bile sistem eski veriyi göstermeye devam edebilir.
Sonuç
Laravel ile sosyal bir ağın temelini oluşturan takip ve arkadaşlık sistemlerini başarıyla kurguladık. İlişkisel veritabanı mantığını ve Eloquent'in gücünü kullanarak, ölçeklenebilir bir yapı kurmuş oldunuz. Bir sonraki adım olarak, bu sistemin üzerine "Gerçek Zamanlı Bildirimler" (Laravel Reverb veya Pusher kullanarak) ekleyerek kullanıcı deneyimini bir üst seviyeye taşıyabilirsiniz.

Yorumlar (0)
Yorum Yaz