16.01.2026

Laravel’de Event-Driven Mimari: Event, Listener ve Subscriber ile Gevşek Bağlı Tasarım

Laravel’in event sistemiyle modüler, test edilebilir ve genişletilebilir bir yapı kurmanın pratik yolları.

Neden Event-Driven?

Uygulama büyüdükçe Controller -> Service -> ... zinciri kalabalıklaşır; bir işlem (ör. sipariş oluşturma) yeni yan etkiler (e-posta, stok düşme, analitik, bildirim) kazandıkça mevcut akışa sürekli kod eklenir. Event-driven yaklaşım, ana iş akışını sade tutar; yan etkileri ayrı listener’lara böler.

Amaç: “Sipariş oluştu” bilgisini yayınla, gerisini aboneler (listener/subscriber) halletsin.


Basit Senaryo: Sipariş Oluştu

1) Event tanımı

php artisan make:event OrderPlaced
// app/Events/OrderPlaced.php
namespace App\Events;

use App\Models\Order;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderPlaced
{
    use Dispatchable, SerializesModels;

    public function __construct(public Order $order) {}
}

2) Listener’lar

Örn: stok düş, e-posta at, analitik kaydet.

php artisan make:listener DecreaseStock --event=OrderPlaced
php artisan make:listener SendOrderConfirmationEmail --event=OrderPlaced

// app/Listeners/DecreaseStock.php
namespace App\Listeners;

use App\Events\OrderPlaced;

class DecreaseStock
{
    public function handle(OrderPlaced $event): void
    {
        foreach ($event->order->items as $item) {
            $item->product->decrement('stock', $item->quantity);
        }
    }
}

3) Event’i tetiklemek

Sipariş kaydedildiği yerde:

use App\Events\OrderPlaced;

$order = Order::create([...]);

OrderPlaced::dispatch($order);

Bu kadar: Sipariş akışını, yan etkilerden bağımsız tutmuş oldun.


Listener’ları Kuyruğa Al: Performans + Dayanıklılık

Bazı işler (mail, üçüncü parti API, raporlama) yavaş olabilir. Listener’ı queue üzerinden çalıştırmak için ShouldQueue kullan.

namespace App\Listeners;

use App\Events\OrderPlaced;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendOrderConfirmationEmail implements ShouldQueue
{
    public int $tries = 3;

    public function handle(OrderPlaced $event): void
    {
        // Mail::to(...)->send(...)
    }
}

Bu yaklaşım, kullanıcıya yanıt süresini kısaltır ve geçici hatalarda otomatik tekrar denemeye imkan verir.


Subscriber Kullan: Aynı Modülün Event’lerini Topla

Listener sayısı arttığında dosya karmaşası oluşabilir. Bir modülün event’lerini tek yerde toplamak için subscriber kullan.

php artisan make:listener OrderSubscriber
// app/Listeners/OrderSubscriber.php
namespace App\Listeners;

use App\Events\OrderPlaced;
use Illuminate\Events\Dispatcher;

class OrderSubscriber
{
    public function onOrderPlaced(OrderPlaced $event): void
    {
        // örn: internal metrics
    }

    public function subscribe(Dispatcher $events): void
    {
        $events->listen(OrderPlaced::class, [self::class, 'onOrderPlaced']);
    }
}

EventServiceProvider içine ekle:

protected $subscribe = [
    \App\Listeners\OrderSubscriber::class,
];


İyi Pratikler (Kısa Notlar)

  • Event adları geçmiş zamanda olsun: OrderPlaced, UserRegistered.
  • Event içine gereksiz veri şişirme: genelde id veya ilgili model yeterli.
  • Listener’lar tek sorumluluk taşısın: “stok düşmek” ile “mail atmak” aynı listener olmasın.
  • Kritik yan etkiler için idempotency düşün: aynı event iki kez işlenirse stok iki kez düşmesin (ör. işlem kaydı tut).

Test Etmesi Kolay

Laravel, event’leri testte kolayca “fake” etmeyi sağlar:

use Illuminate\Support\Facades\Event;
use App\Events\OrderPlaced;

Event::fake();

// sipariş oluşturma aksiyonu...

Event::assertDispatched(OrderPlaced::class);

Bu sayede “sipariş oluşunca event fırlıyor mu?” sorusunu hızlıca doğrularsın.


Sonuç

Event-driven yaklaşım, Laravel projelerinde kodu modülerleştirir, ana akışı sadeleştirir ve yeni özellikleri “mevcut koda dokunmadan” eklemeyi kolaylaştırır. Küçük başlayıp (1 event + 1 listener) büyüterek ilerlemek en sağlıklısıdır.