Gereksinimler ve Ön Hazırlık
Bu projeyi hayata geçirmek için Laravel 11 veya üzeri bir sürüm kullanmanız önerilir. Bildirim tercihleri, genellikle kullanıcı tablosuna bağlı bir ilişkisel yapı gerektirdiği için veritabanı şemanızı bu yönde planlamanız kritik önem taşır.
- Laravel 11+ kurulu bir proje ortamı.
- Veritabanı yönetimi için MySQL veya PostgreSQL.
- Bildirimleri yönetmek için Laravel'in yerleşik
Notificationsınıfı bilgisi. - Redis (kuyruk yönetimi için önerilir).
Adım 1: Veritabanı Şemasını Tasarlama
Kullanıcıların bildirim tercihlerini saklamak için en verimli yöntem, bildirim türlerini ve kanallarını ayrı bir tabloda tutmaktır. Bu sayede yeni bir bildirim türü eklendiğinde kod değişikliği yapmadan veritabanı üzerinden yönetimi sağlayabilirsiniz.
// Migration dosyası: create_user_notification_preferences_table
Schema::create('user_notification_preferences', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('notification_type'); // Örn: 'new_order', 'account_alert'
$table->boolean('mail_enabled')->default(true);
$table->boolean('database_enabled')->default(true);
$table->boolean('sms_enabled')->default(false);
$table->timestamps();
});
Bu yapı, her kullanıcı için her bildirim türünün ayrı ayrı kanallarını yönetmemize olanak tanır. notification_type alanı, sisteminizdeki bildirim olaylarını temsil eder.
Adım 2: Tercihleri Yöneten Model ve İlişki
Kullanıcı modelinizde bu tercihlere kolayca erişebilmek için bir ilişki tanımlamalıyız. Bu, bildirim gönderirken kullanıcının tercihlerini kontrol etmemizi sağlar.
// User.php Model dosyası
public function notificationPreferences()
{
return $this->hasMany(UserNotificationPreference::class);
}
public function getPreference(string $type, string $channel)
{
return $this->notificationPreferences()
->where('notification_type', $type)
->value($channel . '_enabled');
}
getPreference metodu, bildirim gönderilmeden önce kullanıcının o kanalı aktif edip etmediğini hızlıca kontrol etmemizi sağlar. Bu yöntem, gereksiz bildirim trafiğini engellemek için kritiktir.
Adım 3: Dinamik Bildirim Sınıfını Oluşturma
Laravel'in via metodu, bildirimlerin hangi kanallara gideceğini belirler. Burada veritabanı tercihlerini kullanarak dinamik bir yapı kuracağız.
// App\Notifications\OrderShipped.php
public function via($notifiable)
{
$channels = [];
if ($notifiable->getPreference('order_shipped', 'mail')) {
$channels[] = 'mail';
}
if ($notifiable->getPreference('order_shipped', 'database')) {
$channels[] = 'database';
}
return $channels;
}
Bu yaklaşım, bildirim gönderim mantığını merkezi bir yerden yönetmenizi sağlar. Eğer kullanıcı mail bildirimlerini kapattıysa, via metodu o kanalı diziye eklemeyecek ve bildirim mail olarak gitmeyecektir.
Adım 4: Kullanıcı Tercihleri İçin Yönetim Paneli (API/Controller)
Kullanıcıların bu tercihleri güncelleyebilmesi için bir API endpoint'ine ihtiyacımız var. Güvenlik için FormRequest kullanarak gelen verileri doğrulamanız şarttır.
// NotificationPreferenceController.php
public function update(Request $request)
{
$validated = $request->validate([
'type' => 'required|string',
'mail' => 'boolean',
'database' => 'boolean',
]);
$user = $request->user();
$user->notificationPreferences()->updateOrCreate(
['notification_type' => $validated['type']],
[
'mail_enabled' => $validated['mail'],
'database_enabled' => $validated['database'],
]
);
return response()->json(['message' => 'Tercihler güncellendi.']);
}
updateOrCreate metodu, kullanıcının o bildirim türü için daha önce bir kaydı yoksa oluşturur, varsa günceller. Bu, veritabanı tutarlılığını korumak için en güvenli yoldur.
Özellik Karşılaştırma Tablosu
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Veritabanı Bazlı | Esnek, ölçeklenebilir, dinamik | Daha fazla SQL sorgusu |
| Config Bazlı | Hızlı, basit | Kullanıcı bazlı özelleştirme zor |
| Redis Cache Bazlı | Çok yüksek performans | Veri senkronizasyonu karmaşık |
Güvenlik Uyarısı: Kullanıcı tercihlerini güncellerken mutlaka
$request->user()üzerinden yetkilendirme yapın. Doğrudanuser_idparametresi alarak güncelleme yapmak, yetkisiz erişim (IDOR) zafiyetine yol açabilir.
Adım 5: Bildirim Gönderimini Test Etme
Sistemi test etmek için bir birim testi (unit test) yazmak, ileride yapılacak değişikliklerde sistemin bozulmadığından emin olmanızı sağlar.
public function test_notification_preference_is_respected()
{
$user = User::factory()->create();
// Kullanıcı mail bildirimini kapatsın
$user->notificationPreferences()->create([
'notification_type' => 'order_shipped',
'mail_enabled' => false
]);
Notification::fake();
$user->notify(new OrderShipped());
Notification::assertNotSentTo($user, MailChannel::class);
}
Testler, bildirim sisteminizin beklenen şekilde çalışıp çalışmadığını doğrulamak için en güvenilir yoldur. Notification::fake() kullanarak gerçek bir mail göndermeden sistemin mantığını test edebilirsiniz.
Sıkça Sorulan Sorular
Bildirim tercihlerini varsayılan olarak nasıl açık tutabilirim?
Migration dosyanızda default(true) değerini kullanarak veya kullanıcı oluşturulduğunda bir "event listener" ile varsayılan kayıtları veritabanına ekleyerek bu durumu yönetebilirsiniz.
Çok fazla bildirim türü olduğunda veritabanı yavaşlar mı?
Eğer milyonlarca kullanıcınız varsa, notification_type sütununa bir index eklemeyi unutmayın. Ayrıca Redis kullanarak tercihleri önbelleğe almak sorgu yükünü ciddi oranda azaltacaktır.
SMS ve Push bildirimlerini sisteme nasıl dahil ederim?
Aynı user_notification_preferences tablosuna sms_enabled ve push_enabled sütunlarını ekleyip, via metodunda bu sütunları kontrol etmeniz yeterlidir.
Kullanıcı bildirimleri tamamen kapatmak isterse ne yapmalıyım?
Sisteminizde "Tüm bildirimleri kapat" şeklinde bir global tercih sütunu ekleyebilir ve via metodunda ilk olarak bu alanı kontrol edebilirsiniz.
Bildirim tercihleri performansı nasıl etkiler?
Her bildirim gönderiminde veritabanı sorgusu yapmak yerine, kullanıcı nesnesini yüklerken tercihleri de eager loading ile ($user->load('notificationPreferences')) yüklemek performansı artırır.
Bildirim Sistemlerinde Hata Ayıklama ve Loglama Stratejileri
Karmaşık bildirim sistemlerinde, bir kullanıcının neden bildirim almadığını tespit etmek genellikle en zorlu süreçlerden biridir. Kullanıcı tercihleri, veritabanı kilitlenmeleri veya üçüncü taraf API hataları süreci sekteye uğratabilir. Bu nedenle, bildirim gönderim süreçlerinizi izlenebilir kılmak için Laravel'in Log ve Event sistemlerini birleştiren bir yapı kurmalısınız.
Bildirim gönderimlerini bir NotificationSent event'i ile dinleyerek, her gönderim sonucunu veritabanında veya log dosyalarında tutabilirsiniz:
// app/Listeners/LogNotificationStatus.php
namespace App\Listeners;
use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Support\Facades\Log;
class LogNotificationStatus
{
public function handle(NotificationSent $event)
{
Log::info('Bildirim gönderildi:', [
'user_id' => $event->notifiable->id,
'channel' => $event->channel,
'notification' => get_class($event->notification),
'timestamp' => now()
]);
}
}
Bu yapı sayesinde, bir kullanıcı "Bildirim gelmiyor" şikayetiyle geldiğinde, sistem loglarını inceleyerek tercihlerinin o anki durumu ve gönderim kanalının aktif olup olmadığını saniyeler içinde doğrulayabilirsiniz.
İleri Seviye Optimizasyon: Bildirimleri Kuyruğa Alma (Queueing)
Bildirim tercihleri sistemi büyüdükçe, her bildirim gönderimi sırasında veritabanı sorgusu yapmak ve tercihleri kontrol etmek uygulamanın yanıt süresini uzatabilir. Bunu engellemek için bildirimlerinizi mutlaka ShouldQueue arayüzü ile asenkron hale getirmelisiniz.
Ancak, asenkron yapıda "tercihlerin güncelliği" kritik bir sorundur. Bildirim kuyruğa alındığı an ile gönderildiği an arasında kullanıcı tercihlerini değiştirirse ne olur? Bu riski yönetmek için tercihi bildirim sınıfının içinde, gönderim anında tekrar kontrol etmelisiniz:
// app/Notifications/NewCommentNotification.php
public function shouldSend($notifiable, $channel)
{
// Gönderim anında veritabanından güncel tercihi tekrar çek
$preference = $notifiable->preferences()
->where('type', 'new_comment')
->first();
return $preference ? $preference->is_enabled : false;
}
Bu yöntem, kuyrukta bekleyen binlerce bildirim olsa bile, gönderim anında kullanıcının o anki tercihlerinin geçerli olmasını sağlar. Ayrıca, Redis gibi bir sürücü kullanarak bu tercih sorgularını önbelleğe (cache) alırsanız, veritabanı üzerindeki yükü %90 oranında azaltabilirsiniz.
Önbellekleme İpucu
Kullanıcı tercihlerini her seferinde SQL sorgusu ile çekmek yerine, Cache::remember kullanarak belirli bir süre (örneğin 1 saat) bellekte tutun. Tercih güncellendiğinde ise ilgili kullanıcının cache anahtarını temizleyin:
// Tercih güncellendiğinde cache temizliği
public function updatePreference($userId, $type, $value)
{
$preference = Preference::updateOrCreate([...]);
Cache::forget("user_{$userId}_preferences");
return $preference;
}
Sonuç
Laravel ile gelişmiş bir bildirim tercihleri sistemi kurmak, kullanıcılarınıza sunduğunuz değeri artıran profesyonel bir yaklaşımdır. Veritabanı odaklı bu tasarım, uygulamanız büyüdükçe yeni bildirim türleri eklemenize ve mevcut kanalları kolayca yönetmenize olanak tanır. Unutmayın, iyi bir yazılım mimarisi, değişime dirençli değil, değişime uyumlu olandır.
Sorumluluk Reddi: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce gerekli güvenlik testlerini yapmalı, girdi doğrulamalarını (validation) sıkılaştırmalı ve veritabanı indekslerini optimize etmelisiniz.
Bir sonraki adım olarak, bu tercihleri kullanıcı arayüzünde (Vue.js veya Livewire ile) gerçek zamanlı güncelleyen bir "Settings" sayfası tasarlayabilirsiniz.


Yorumlar (0)
Yorum Yaz