Laravel Events i Listeners w 2026: Architektura Zdarzeniowa i Pytania Rekrutacyjne

Kompleksowy przewodnik po systemie zdarzeń i nasłuchiwaczy w Laravel 12. Implementacja wzorca obserwatora, kolejkowanie listenerów, transakcje bazodanowe oraz pytania na rozmowy kwalifikacyjne.

Laravel Events i Listeners - architektura zdarzeniowa

System zdarzeń i nasłuchiwaczy w Laravel implementuje wzorzec obserwatora, oddzielając komponenty aplikacji poprzez umożliwienie różnym częściom systemu reagowania na akcje bez bezpośrednich zależności. Gdy użytkownik składa zamówienie, zdarzenie OrderShipped jest wywoływane, a osobne nasłuchiwacze obsługują powiadomienia, analizy i aktualizacje magazynu niezależnie od siebie.

Automatyczne Wykrywanie Zdarzeń w Laravel 12

Laravel 12 automatycznie wykrywa nasłuchiwaczy w katalogu app/Listeners. Każda klasa posiadająca metodę handle lub __invoke z type hintem na klasę zdarzenia zostaje automatycznie zarejestrowana, bez potrzeby pliku konfiguracyjnego.

Jak Działa Automatyczne Wykrywanie Zdarzeń w Laravel 12

Od Laravel 11 nie ma już EventServiceProvider. Framework skanuje katalog Listeners i używa refleksji do określenia, na które zdarzenia reaguje każdy nasłuchiwacz, bazując na type hincie w sygnaturze metody handle.

app/Listeners/SendOrderConfirmation.phpphp
<?php

namespace App\Listeners;

use App\Events\OrderShipped;

class SendOrderConfirmation
{
    public function handle(OrderShipped $event): void
    {
        // Wysłanie emaila potwierdzającego do $event->order->user
    }
}

Powyższy nasłuchiwacz zostaje automatycznie zarejestrowany dla zdarzeń OrderShipped. Nie wymaga to ręcznego bindowania w service providerze. Takie podejście redukuje boilerplate i utrzymuje relacje zdarzenie-nasłuchiwacz blisko implementującego je kodu.

Aby zweryfikować zarejestrowanych nasłuchiwaczy, należy uruchomić php artisan event:list. W środowisku produkcyjnym warto zbuforować manifest zdarzeń poleceniem php artisan event:cache, aby uniknąć skanowania katalogu przy każdym żądaniu.

Tworzenie Zdarzeń i Nasłuchiwaczy za Pomocą Artisana

Laravel udostępnia komendy Artisan do generowania szkieletu zdarzeń i nasłuchiwaczy:

bash
# Generowanie klasy zdarzenia
php artisan make:event OrderShipped

# Generowanie nasłuchiwacza powiązanego ze zdarzeniem
php artisan make:listener SendShipmentNotification --event=OrderShipped

Wygenerowana klasa zdarzenia wykorzystuje trzy traity: Dispatchable dla statycznej metody dispatch(), InteractsWithSockets dla broadcastingu oraz SerializesModels do serializacji modeli Eloquent gdy nasłuchiwacze są kolejkowane.

app/Events/OrderShipped.phpphp
<?php

namespace App\Events;

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

class OrderShipped
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

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

Klasa zdarzenia to kontener na dane. Przechowuje model Order i nic więcej. Logika biznesowa należy do nasłuchiwaczy, nie do zdarzeń.

Wysyłanie Zdarzeń z Kontrolerów i Serwisów

Zdarzenia wysyła się za pomocą statycznej metody dispatch() na klasie zdarzenia:

app/Http/Controllers/OrderController.phpphp
<?php

namespace App\Http\Controllers;

use App\Events\OrderShipped;
use App\Models\Order;
use Illuminate\Http\Request;

class OrderController extends Controller
{
    public function ship(Request $request, Order $order)
    {
        // Logika wysyłki...
        
        OrderShipped::dispatch($order);
        
        return redirect()->route('orders.index');
    }
}

Do warunkowego wysyłania służą metody dispatchIf() lub dispatchUnless():

php
// Wysyłaj tylko jeśli zamówienie ma numer śledzenia
OrderShipped::dispatchIf($order->tracking_number !== null, $order);

Gotowy na rozmowy o Laravel?

Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.

Kolejkowane Nasłuchiwacze dla Wolnych Operacji

Nasłuchiwacze wysyłające emaile, wywołujące zewnętrzne API lub wykonujące ciężkie obliczenia powinny działać asynchronicznie. Implementacja ShouldQueue umieszcza nasłuchiwacza w kolejce:

app/Listeners/SendShipmentNotification.phpphp
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    public $queue = 'notifications';
    public $delay = 60; // Czekaj 60 sekund przed przetworzeniem

    public function handle(OrderShipped $event): void
    {
        // Wysłanie powiadomienia do $event->order->user
    }
}

Konfiguracja połączenia i nazwy kolejki odbywa się przez właściwości $connection i $queue, lub przez metody runtime:

php
public function viaConnection(): string
{
    return 'redis';
}

public function viaQueue(): string
{
    return $this->event->order->priority === 'high' 
        ? 'high-priority' 
        : 'default';
}

Warunkowe Kolejkowanie z shouldQueue

Czasami nasłuchiwacz powinien być kolejkowany tylko na podstawie danych zdarzenia:

php
public function shouldQueue(OrderShipped $event): bool
{
    // Kolejkuj tylko dla zamówień powyżej 100$
    return $event->order->total >= 10000;
}

Transakcje Bazodanowe i Timing Zdarzeń

Kolejkowani nasłuchiwacze wysłani wewnątrz transakcji mogą być przetwarzani zanim transakcja zostanie zatwierdzona, co powoduje błędy brakujących danych. Istnieją dwa rozwiązania:

1. Konfiguracja globalna w config/queue.php:

php
'connections' => [
    'redis' => [
        'after_commit' => true,
    ],
],

2. Per-listener z ShouldQueueAfterCommit:

php
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;

class UpdateInventory implements ShouldQueueAfterCommit
{
    public function handle(OrderShipped $event): void
    {
        // Bezpieczne odpytywanie zamówienia, transakcja jest zatwierdzona
    }
}

Dla samych zdarzeń należy zaimplementować ShouldDispatchAfterCommit na klasie zdarzenia:

php
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;

class OrderShipped implements ShouldDispatchAfterCommit
{
    // Zdarzenie wysyłane tylko po zatwierdzeniu transakcji
}

Unikalni Nasłuchiwacze dla Zapobiegania Duplikatom

Interfejs ShouldBeUnique zapobiega kolejkowaniu duplikatów nasłuchiwaczy gdy jeden już jest przetwarzany:

php
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessLicenseKey implements ShouldQueue, ShouldBeUnique
{
    public $uniqueFor = 3600; // Blokada wygasa po 1 godzinie

    public function uniqueId(LicensePurchased $event): string
    {
        return 'license:' . $event->license->id;
    }

    public function handle(LicensePurchased $event): void
    {
        // Generowanie i przypisanie klucza licencji
    }
}

Jeśli to samo ID licencji wywołuje wiele zdarzeń w krótkim czasie, tylko pierwszy nasłuchiwacz przetwarza. Kolejne próby wykrywają trzymaną blokadę i pomijają kolejkowanie.

Subskrybenci Zdarzeń dla Powiązanych Zdarzeń

Gdy wiele powiązanych zdarzeń współdzieli wspólną logikę obsługi, subskrybenci zdarzeń grupują handlery w jednej klasie:

app/Listeners/UserActivitySubscriber.phpphp
<?php

namespace App\Listeners;

use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Illuminate\Events\Dispatcher;

class UserActivitySubscriber
{
    public function handleLogin(Login $event): void
    {
        // Logowanie udanego logowania, aktualizacja last_login
    }

    public function handleLogout(Logout $event): void
    {
        // Logowanie wylogowania, czyszczenie danych sesji
    }

    public function subscribe(Dispatcher $events): array
    {
        return [
            Login::class => 'handleLogin',
            Logout::class => 'handleLogout',
        ];
    }
}

Subskrybenci podlegają regułom automatycznego wykrywania. Jeśli metody handlerów w klasie subskrybenta mają prawidłowo typowane parametry, Laravel rejestruje je automatycznie.

Nasłuchiwanie Wielu Zdarzeń z Union Types

Pojedynczy nasłuchiwacz może reagować na wiele typów zdarzeń używając union types z PHP 8:

php
public function handle(OrderShipped|OrderCancelled $event): void
{
    match (true) {
        $event instanceof OrderShipped => $this->notifyShipped($event),
        $event instanceof OrderCancelled => $this->notifyCancelled($event),
    };
}

Ten wzorzec sprawdza się przy powiadomieniach, które podążają za podobną logiką dla różnych typów zdarzeń.

Odraczanie Zdarzeń z Event::defer

Laravel 12 wprowadził Event::defer() do opóźniania wysyłki zdarzeń do momentu zakończenia bloku kodu. Zapewnia to nasłuchiwaczom dostęp do wszystkich powiązanych rekordów:

php
use Illuminate\Support\Facades\Event;

Event::defer(function () {
    $user = User::create(['name' => 'John']);
    $user->posts()->create(['title' => 'Welcome']);
});
// Zdarzenia dla utworzenia User i Post wysyłane są tutaj

Jeśli wewnątrz closure wystąpi wyjątek, odroczone zdarzenia nigdy nie zostaną wysłane.

Zacznij ćwiczyć!

Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.

Pytania Rekrutacyjne o Laravel Events i Listeners

Rozmowy techniczne często testują zrozumienie architektury zdarzeniowej. Oto pytania odróżniające doświadczonych programistów Laravel:

P: Jak Laravel 12 rejestruje nasłuchiwaczy bez EventServiceProvider?

Laravel skanuje app/Listeners używając refleksji. Odczytuje type hint na metodach handle() lub __invoke() aby określić, na które zdarzenie reaguje każdy nasłuchiwacz. W produkcji manifest należy zbuforować poleceniem php artisan event:cache.

P: Kiedy nasłuchiwacz powinien implementować ShouldQueue?

Zawsze gdy operacja trwa dłużej niż kilka milisekund: wysyłanie emaili, wywoływanie zewnętrznych API, generowanie raportów lub przetwarzanie plików. Synchroniczni nasłuchiwacze blokują odpowiedź HTTP.

P: Jaki problem rozwiązuje ShouldQueueAfterCommit?

Kolejkowani nasłuchiwacze mogą być przetwarzani zanim transakcja bazodanowa zostanie zatwierdzona. Jeśli nasłuchiwacz odpytuje o właśnie utworzony rekord, to się nie powiedzie bo dane nie są jeszcze zatwierdzone. ShouldQueueAfterCommit opóźnia wysyłkę do kolejki do momentu zakończenia transakcji.

P: Jak zapobiegać duplikatom przetwarzania tego samego zdarzenia?

Należy zaimplementować ShouldBeUnique. Metoda uniqueId() powinna zwracać klucz cache bazujący na danych zdarzenia. Nasłuchiwacz nabywa atomową blokadę, a duplikaty wysyłek są pomijane jeśli blokada jest trzymana.

P: Jaka jest różnica między listenerem a subskrybentem zdarzeń?

Listener obsługuje jeden typ zdarzenia. Subskrybent to klasa rejestrująca handlery dla wielu powiązanych zdarzeń w jednym miejscu, przydatna do grupowania zdarzeń autentykacji lub logowania audytowego.

Znaczenie Laravel Events dla Skalowalnych Aplikacji

  • Zdarzenia oddzielają komponenty, pozwalając funkcjom takim jak powiadomienia i analityka ewoluować niezależnie
  • Kolejkowani nasłuchiwacze przenoszą wolne operacje, utrzymując szybkie odpowiedzi HTTP
  • ShouldQueueAfterCommit zapobiega race conditions między workerami kolejki a transakcjami bazodanowymi
  • Automatyczne wykrywanie w Laravel 12 usuwa narzut konfiguracyjny, utrzymując logikę nasłuchiwaczy blisko implementacji
  • Subskrybenci zdarzeń konsolidują powiązaną obsługę zdarzeń, redukując rozproszenie plików dla typowych wzorców jak śledzenie aktywności użytkownika
  • Moduł /technologies/laravel/interview-questions/events-listeners na SharpSkill obejmuje te wzorce z interaktywnymi pytaniami
Wyzwanie dnia

Znajdziesz błąd w Laravel?

Prawdziwy fragment kodu, ukryty błąd, jedna próba dziennie. Bez konta, żeby spróbować.

Anthony Fillion-Maillet

Autor:

Anthony Fillion-Maillet

Założyciel SharpSkill

Programista fullstack od ponad 10 lat. Prowadzi SharpSkill i odpowiada za wszystko, co się tu ukazuje.

Zaktualizowano 20 sierpnia 2026

Tagi

#laravel
#events
#listeners
#php
#architektura zdarzeniowa

Udostępnij

Powiązane artykuły