Laravel'de bildirimler (notifications): e-posta ve SMS
Laravel Notification sınıflarıyla aynı bildirim mantığını e-posta, SMS gibi birden çok kanaldan nasıl gönderdiğimi anlatıyorum.
Bir uygulama büyüdükçe bildirim ihtiyacı da çeşitleniyor: sipariş onayı e-posta ile gitsin, kargo bildirimi SMS ile gitsin, yorum bildirimi ise uygulama içi bildirim olsun. Laravel’in notification sistemiyle bu farklı kanalları tek bir sınıf üzerinden yönetmek mümkün. Kanalı çoğaltmak, mevcut bildirimi bozmak zorunda kalmadan yapılıyor — bu yapının asıl değeri bu.
Bildirim sistemi nasıl çalışır?
Laravel’de her bildirim bir sınıftır. Bu sınıf, hangi kanallardan gönderileceğini ve her kanalda nasıl görüneceğini tanımlar. Artisan komutuyla bir iskelet üretebilirsiniz:
php artisan make:notification OrderShipped
Oluşan sınıf app/Notifications/OrderShipped.php yolunda yer alır. İki kritik metot içerir: via ve toMail (ya da toNexmo, toBroadcast gibi kanal metodları).
E-posta bildirimi
via metodu hangi kanalların kullanılacağını döndürür. toMail metodu ise posta mesajını oluşturur:
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class OrderShipped extends Notification
{
protected $order;
public function __construct($order)
{
$this->order = $order;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Siparişiniz kargoya verildi')
->line('Siparişiniz ' . $this->order->tracking_number . ' takip numarasıyla kargoya verildi.')
->action('Siparişi Takip Et', url('/orders/' . $this->order->id))
->line('Alışverişiniz için teşekkür ederiz.');
}
}
Bildirimi bir kullanıcıya göndermek için notify metodu yeterli:
<?php
$user->notify(new OrderShipped($order));
notify metodu, Notifiable trait’ini kullanan her model için otomatik olarak geliyor. User modeli bu trait’i varsayılan olarak içeriyor.
SMS kanalı eklemek
Aynı bildirimi SMS olarak da göndermek istediğinizde via metoduna SMS kanalını eklemeniz yeterli. Laravel, Nexmo (şimdiki adıyla Vonage) entegrasyonuyla birlikte geliyor:
<?php
public function via($notifiable)
{
return ['mail', 'nexmo'];
}
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Siparişiniz ' . $this->order->tracking_number . ' numarasıyla kargoya verildi.');
}
toMail metodunu değiştirmeden SMS kanalını ekledim. Bildirim mantığı tek yerde, kanallar ayrı metodlarda — bu ayrım sağlam.
Kanalı kullanıcıya göre belirlemek
Gerçek projelerde her kullanıcı her kanalı istemeyebilir. Biri SMS almak istemiyordur, diğeri yalnızca e-posta tercih ediyordur. via metodu $notifiable nesnesini parametre olarak alıyor; kullanıcı tercihlerine göre karar verebilirsiniz:
<?php
public function via($notifiable)
{
$channels = ['mail'];
if ($notifiable->sms_notifications_enabled) {
$channels[] = 'nexmo';
}
return $channels;
}
Bu sayede bildirim sınıfı değişmeden, kullanıcı tablosundaki bir sütun kanal listesini belirliyor.
Veritabanı bildirimleri
Uygulamanızın içinde bildirim kutucuğu göstermek istiyorsanız, database kanalı bunu sağlıyor. Bildirimler notifications tablosuna kaydediliyor; okunmamış bildirim sayısını, listesini sorgulamak kolaylaşıyor.
<?php
public function via($notifiable)
{
return ['mail', 'database'];
}
public function toArray($notifiable)
{
return [
'order_id' => $this->order->id,
'tracking_number' => $this->order->tracking_number,
];
}
<?php
// Okunmamış bildirimleri çekmek
$user->unreadNotifications;
// Tüm bildirimleri okunmuş işaretlemek
$user->unreadNotifications->markAsRead();
database kanalını ilk kullandığımda bir şeyi gözden kaçırdım: notifications tablosunun oluşturulması için migration çalıştırmak gerekiyor. Laravel php artisan notifications:table komutuyla bu migration’ı üretiyor. Bildirimlerin sessizce kaybolduğunu bir süre anlayamadım; tablo yoktu.
Kuyruk ile asenkron gönderim
E-posta ve SMS gönderimi zaman alan işlemler. Bir kullanıcı sipariş verdiğinde yanıtın beklememesi için bildirimleri queue’ya alabileceğinizi belirtmeden geçmeyeyim. Bildirim sınıfınızın ShouldQueue arayüzünü implement etmesi yeterli:
<?php
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderShipped extends Notification implements ShouldQueue
{
// ...
}
Kuyruk altyapısı ayrı bir konu; bu yazıda detayına girmeyi planlamıyorum, ama ShouldQueue satırını eklemek gerçek projelerde hemen uygulanabilir ilk adım.
Sonuç
Laravel’in bildirim sistemi, “hangi kanaldan gönderilecek” kararını tek bir sınıfta toplaması bakımından çok temiz bir tasarıma sahip. Yeni bir kanal eklemek mevcut mantığı değiştirmiyor; sadece yeni bir metod geliyor. Proje büyüdükçe, bildirim türleri çoğaldıkça bu ayrımın değeri katlanarak artıyor. Eski yaklaşımda her kanal için ayrı kod yazıyordum ve bir değişiklik her birini ayrı ayrı güncellemeyi gerektiriyordu; artık bildirim mantığı tek yerde.
Bildirim sınıfları büyüdükçe dikkat edilmesi gereken bir şey daha var: via metodu içinde channel kararı sadece kullanıcı tercihinden değil, bildirimin kendisine bağlı koşullardan da etkilenebilir. Örneğin sipariş tutarı belirli bir eşiği aşıyorsa SMS de gönderilsin, altındaysa yalnızca e-posta gitsin gibi bir mantık kurulabilir. Bu karar via içinde kalıyorsa bildirim sınıfı şişebilir; böyle durumlarda farklı bildirim sınıfları oluşturup hangisinin gönderileceği kararını çağıran kodda vermek daha temiz bir ayrım sağlıyor. Bildirim sınıfı “nasıl gönderilir” sorusunu bilmeli; “ne zaman ve hangi koşulda gönderilir” sorusu onu çağıran iş mantığının işi.