Eğer Laravel’i yeni yeni öğreniyorsanız veya bildirim gönderme konusunda bilgi sahibi değilseniz ilk inceleyeceğiniz makaleler ve videolarda nasıl kolayca yapıldığını görebilirsiniz ama bazen mantığını kavrayamayabilirsiniz. Laravel’de bildirim için hem Event hem de Notification kullanılabiliyor. Pusher, Socket.io veya diğer birçok yöntemle bildirim ve canlı mesajlaşma sistemi kurulabiliyor. Her ikisiyle de birebir aynı iş yapılabiliyorsa gayet doğal bir şekilde neden bunlar 2 tane diye sorabilirsiniz. Şimdi bunları iyice anlamaya çalışalım.
Notification
İlk olarak konuya doğrudan tercüme ile başlayalım. Notification sözcüğünü Bildirim olarak tercüme ediyoruz. Türkçe olarak Bildirim’i tanımlayacak olursak; bir işin sonucunda işin sonucunu veya herhangi bir haberi karşı tarafa iletmeye Bildirim diyebiliriz. Örneğin; aylık ödemeli bir sistemden hizmet alıyorsam ay sonuna yakın bir tarihte sistem bana ödememin yaklaştığını e-posta yoluyla haber verirse bu bir bildirimdir diyebiliriz. Aynı şekilde Facebok veya Twitter gibi sosyal medyalarda bir arkadaşım benim paylaşımıma yorum yaparsa ve site bu yorumun haberini bana verirse bu da bir bildirim olur.
Bildirimler canlı da olabilir, gecikmeli de olabilir. E-posta, sms veya herhangi başka bir yolla da olabilir. Yöntemi fark etmeksizin haber iletme işine bildirim diyoruz.
Event
Yine ilk olarak tercüme ile başlarsak Event sözcüğünü “Etkinlik” veya “Olay” olarak çevirebiliriz. Biz günlük konuşmalarımızda etkinliği planlı veya plansız bir araya gelerek birşeyler yapma olarak tanımlıyor, olayı ise yine planlı veya plansız bir işin/oluşun gerçekleşmesi olarak tanımlıyoruz.
Event ve Notification sözcüklerini incelediğimize göre artık Laravel üzerinden devam edebiliriz.
Laravel’de eğer bir bildirim göndermek istiyorsak bunun en doğru yöntemi Notification kullanmaktır. Laravel bize Notification sınıfı içinde e-posta ile gönderme, veritabanına kaydetme ve socket ile gönderme gibi birkaç özellik daha sunuyor. Eğer gerekli işlemleri yaptıysanız aynı anda birkaç farklı yöntemi birlikte kullanarak tek sınıf üzerinden bildirim de gönderebiliyorsunuz.
Bir örnek üzerinden ilerlemek için küçük bir e-ticaret sitesi geliştirdiğimizi varsayalım. Bu site içerisinde bir kullanıcı bir ürünü satın alsın. Bu durumda senaryonu şöyle olabilir;
Öncelikle sepet işlemleri tamamlanır ve veritabanına kaydedilir. Ardından bir olay tetiklenir.
1 2 3 4 |
$basket = new Basket(); // ... $basket->save(); event(new \App\Events\ProductPurchasedEvent($basket)); |
Bu Event php artisan make:event ProductPurchasedEvent
komutuyla oluşturulunca aşağıdaki gibi bir içerikle gelir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class ProductPurchasedEvent { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct() { // } public function broadcastOn() { return new PrivateChannel('channel-name'); } } |
Eğer Event ile bir bildirim göndermek isterseniz broadcastOn
içerisinde gerekli değişikliği yapıp gönderebilirsiniz ama biz öyle yapmayacağız. Bu haliyle bırakıp ilerleyelim.
Event ardından php artisan make:listener ProductPurchasedEventListener
komutuyla bir Listener oluşturalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php namespace App\Listeners; use App\Models\Basket; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class ProductPurchasedEventListener { public Basket $basket; public function __construct(Basket $basket) { $this->basket = $basket; } public function handle($event) { stoktanUrunEksilt(); eFaturaHazirla(); kargoTakipNumarasiOlustur(); $basket->user()->notify(new \App\Notifications\ProductPurchasedNotification($basket)); } } |
Bu kısımda biraz durup incelememiz gerekiyor.
Biz az önce sepeti kaydettikten sonra Laravel’e dedik ki ProductPurchasedEvent
adında bir olay gerçekleşti. Eğer ProductPurchasedEventListener
sınıfını yazmazsak hiçbir şey olmaz. Laravel bize “eee banane. olay olduysa sana oldu bana bir şey olmadı” gibi bir cevap vererek bir eylem gerçekleştirmez. Bu şekilde cevap vermemesi için biz o olayı dinleyip bizim verdiğimiz görevleri yerine getirecek ProductPurchasedEventListener
sınıfını yazmak zorundayız. Hatta ek olarak bir de olay gerçekleştiğinde onu dinlemesi gereken sınıfı \App\Providers\EventServiceProvider
içinde belirtmemiz gerekiyor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php namespace App\Providers; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { protected $listen = [ // ... \App\Events\ProductPurchasedEvent::class => [ \App\Listeners\ProductPurchasedEventListener::class, ], // ... ]; public function boot() { parent::boot(); } } |
Böylelikle bir olay gerçekleştiğinde artık aşağıdaki kodlar sırasıyla çalışmaya başlayacaktır.
1 2 3 4 5 6 |
public function handle($event) { stoktanUrunEksilt(); eFaturaHazirla(); kargoTakipNumarasiOlustur(); $basket->user()->notify(new \App\Notifications\ProductPurchasedNotification($basket)); } |
Burada gördüğünüz gibi birkaç farklı iş olabilir. Zaten Event sınıfnın asıl kullanılma amacı budur. Bir olay gerçekleştiğinde onun ardından yapılması gereken başka işler varsa o işlerin tamamı burada yazılabilir. Ayrıca bir olayı birden fazla Listener dinleyebilir. Örneğin modüler bir sisteminizin olduğunu düşünelim. Kullanıcı, Sepet ve Ürün modüllerimiz olsun. Bu satın alma işlemi de Sepet modülü içinde kullanıcının kredi puanlarıyla gerçekleşsin. Bu durumda Kullanıcı modülündeki bir listener ProductPurchasedEventListener
sınıfını dinleyerek kredi azaltma işlemini gerçekleştirebilir, Ürün modülündeki bir başka listener stokta azaltma yapabilir, Sepet modülünde ise bildirim gönderme tetiklenebilir. Bu yöntemler tamamen sizin hayal gücünüze kalıyor. İstediğiniz gibi modelleyebilirsiniz.
1 |
$basket->user()->notify(new \App\Notifications\ProductPurchasedNotification($basket)); |
Kodumuza dönerek bu satırı inceleyelim. Bu satın alma işleminde buraya kadar hiç bildirim göndermedik. Hep yapılması gereken başka işleri tamamladık. Artık bildirim gönderme işini o işte uzman olan sınıfa bırakarak bildirimimizi gönderip süreci tamamlayabiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<?php namespace App\Notifications; use App\Models\Basket; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; class ProductPurchasedNotification extends Notification { use Queueable; public Basket $basket; public function __construct(Basket $basket) { $this->basket = $basket; } public function via($notifiable) { return ['mail', 'database', 'broadcast']; } public function toMail($notifiable) { return (new MailMessage)->line('Siparişiniz tamamlandı.'); } public function toBroadcast($notifiable) { return [ 'title' => 'Siparişiniz Hazırlanıyor..', 'message' => $this->basket->number . ' numaralı siparişiniz hazırlanma aşamasında.', ]; } public function toArray($notifiable) { return [ 'user_id' => $this->basket->user()->id, 'xxx' => 'yyy', ]; } } |
ProductPurchasedNotification
ile gerçek bildirimimizi 3 farklı yöntemle göndermiş olduk. Böylelikle Event ve Notification arasındaki farkı araya Listener sınıfını da sıkıştırarak bir örnekle öğrenmiş olduk.
Herhangi bir sorunuz olursa yorum yoluyla ulaşabilirsiniz.
Faydalı olması dileğiyle..
Merhaba, Makele için çok teşekkürler. Bir sorum var tüm bu eventler arka taraftami gerçekleşiyor ?
Örnek: 100 kişiye e-post gönderirken bir az fazla zaman alıyor, bu event ve listeneri kullanırsek her şey arka tarafta geçekleşir. doğrumu ?
Merhaba,
Evet arka tarafta gerçekleşiyor diyebiliriz. Bu tamamen sizin yazılımı nasıl geliştirdiğinize bağlı. Eğer bir request ile event tetiklenirse ve bu job ile çalıştırılırsa arkada gerçekleşir ve o anki request beklemeden response ile tamamlanır. Yok eğer herhangi bir job kullanmadan bir event içinde yine beklemeye sebep olacak yanlış bir tasarım ile bir kod geliştirdiyseniz request tamamlanmadan beklemeye devam eder.