Laravel Events e Listeners 2026: Architettura Event-Driven e Domande da Colloquio

Guida completa a Laravel Events e Listeners nel 2026. Architettura Event-Driven, Observer Pattern, Broadcasting e le domande più frequenti nei colloqui tecnici con esempi di codice.

Laravel Events e Listeners Architettura Event-Driven Diagramma

Il sistema di eventi di Laravel rappresenta un pilastro fondamentale per costruire applicazioni scalabili e manutenibili. In un contesto dove microservizi e elaborazione asincrona sono diventati lo standard, Events e Listeners permettono una comunicazione flessibile e disaccoppiata tra le diverse componenti di un'applicazione. Laravel 12 ha raffinato ulteriormente questo sistema, introducendo typed Events, Broadcasting migliorato e integrazione nativa con le Queue. Questo articolo esplora i fondamenti degli eventi Laravel, pattern avanzati e le domande più comuni nei colloqui tecnici.

Gli eventi disaccoppiano la logica di business

L'Observer Pattern, alla base del sistema di eventi Laravel, permette di reagire ad azioni senza modificare direttamente il codice che le genera. Quando un utente si registra, un evento può essere emesso e molteplici Listener possono reagire: invio email, tracciamento analytics, sincronizzazione CRM. Il codice di registrazione rimane snello e focalizzato sulla sua responsabilità principale.

Creazione di Events e Listeners

Laravel fornisce comandi Artisan per generare rapidamente Events e Listeners. Un Event rappresenta un'azione avvenuta nell'applicazione, mentre un Listener reagisce a quell'evento eseguendo operazioni specifiche.

bash
php artisan make:event OrderPlaced
php artisan make:listener SendOrderConfirmation --event=OrderPlaced
php artisan make:listener UpdateInventory --event=OrderPlaced
php artisan make:listener NotifyWarehouse --event=OrderPlaced

La classe Event contiene i dati rilevanti che vengono passati a tutti i Listeners. Laravel 12 supporta typed properties e Constructor Property Promotion per un codice più conciso.

php
<?php

namespace App\Events;

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

class OrderPlaced
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Order $order,
        public float $totalAmount,
        public string $currency = 'EUR'
    ) {}
}

Il Listener associato implementa il metodo handle, che riceve l'evento come parametro. La dichiarazione dei tipi abilita l'autocompletamento IDE e l'analisi statica.

php
<?php

namespace App\Listeners;

use App\Events\OrderPlaced;
use App\Mail\OrderConfirmation;
use Illuminate\Support\Facades\Mail;

class SendOrderConfirmation
{
    public function handle(OrderPlaced $event): void
    {
        Mail::to($event->order->user->email)
            ->queue(new OrderConfirmation($event->order));
    }
}

Registrazione Eventi e Auto-Discovery

Laravel 12 offre due metodi per registrare gli eventi: registrazione esplicita nell'EventServiceProvider e discovery automatica. Il metodo esplicito offre maggiore controllo e chiarezza.

php
<?php

namespace App\Providers;

use App\Events\OrderPlaced;
use App\Events\PaymentProcessed;
use App\Listeners\NotifyWarehouse;
use App\Listeners\SendOrderConfirmation;
use App\Listeners\UpdateInventory;
use App\Listeners\SendPaymentReceipt;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        OrderPlaced::class => [
            SendOrderConfirmation::class,
            UpdateInventory::class,
            NotifyWarehouse::class,
        ],
        PaymentProcessed::class => [
            SendPaymentReceipt::class,
        ],
    ];

    public function shouldDiscoverEvents(): bool
    {
        return false; // Registrazione esplicita preferita
    }
}

Per la discovery automatica, Laravel analizza le classi Listener e determina a quali eventi rispondono basandosi sulla firma del metodo handle. Questo approccio è adatto per progetti piccoli o prototipazione rapida.

php
public function shouldDiscoverEvents(): bool
{
    return true;
}

protected function discoverEventsWithin(): array
{
    return [
        $this->app->path('Listeners'),
        $this->app->path('Modules/Orders/Listeners'),
    ];
}

Queued Listeners per Elaborazione Asincrona

Operazioni che richiedono tempo come l'invio di email o chiamate ad API esterne non dovrebbero essere elaborate in modo sincrono. Implementando l'interfaccia ShouldQueue, i Listeners vengono automaticamente accodati.

php
<?php

namespace App\Listeners;

use App\Events\OrderPlaced;
use App\Services\InventoryService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class UpdateInventory implements ShouldQueue
{
    use InteractsWithQueue;

    public string $queue = 'inventory';
    public int $tries = 3;
    public int $backoff = 60;

    public function __construct(
        private InventoryService $inventoryService
    ) {}

    public function handle(OrderPlaced $event): void
    {
        foreach ($event->order->items as $item) {
            $this->inventoryService->decrementStock(
                $item->product_id,
                $item->quantity
            );
        }
    }

    public function failed(OrderPlaced $event, \Throwable $exception): void
    {
        // Log errore, notifica admin, azione compensativa
        logger()->error('Aggiornamento inventario fallito', [
            'order_id' => $event->order->id,
            'error' => $exception->getMessage(),
        ]);
    }
}

La configurazione di queue, tentativi di retry e tempo di backoff permette una gestione robusta degli errori. Il metodo failed viene invocato quando tutti i tentativi sono esauriti.

Model Events e Observers

I modelli Eloquent emettono automaticamente eventi durante le operazioni CRUD. Questi Model Events permettono di reagire alle modifiche del database senza alterare il codice dei controller.

php
<?php

namespace App\Models;

use App\Events\OrderPlaced;
use App\Observers\OrderObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Model;

#[ObservedBy(OrderObserver::class)]
class Order extends Model
{
    protected $dispatchesEvents = [
        'created' => OrderPlaced::class,
    ];
}

Le classi Observer raggruppano tutti gli handler di eventi per un Model in un unico punto centrale. Laravel 12 supporta l'attributo ObservedBy per una registrazione dichiarativa.

php
<?php

namespace App\Observers;

use App\Models\Order;
use App\Services\AuditLogService;

class OrderObserver
{
    public function __construct(
        private AuditLogService $auditLog
    ) {}

    public function creating(Order $order): void
    {
        $order->order_number = $this->generateOrderNumber();
    }

    public function created(Order $order): void
    {
        $this->auditLog->log('order.created', $order);
    }

    public function updating(Order $order): void
    {
        if ($order->isDirty('status')) {
            $order->status_changed_at = now();
        }
    }

    public function deleted(Order $order): void
    {
        $this->auditLog->log('order.deleted', $order);
    }

    private function generateOrderNumber(): string
    {
        return 'ORD-' . date('Ymd') . '-' . strtoupper(uniqid());
    }
}

Event Broadcasting per Aggiornamenti Real-Time

Laravel Broadcasting permette di trasmettere eventi server-side ai client frontend tramite WebSocket. Questo è essenziale per dashboard in tempo reale, applicazioni chat e notifiche live.

php
<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderStatusUpdated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Order $order,
        public string $previousStatus,
        public string $newStatus
    ) {}

    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('orders.' . $this->order->user_id),
            new Channel('admin.orders'),
        ];
    }

    public function broadcastAs(): string
    {
        return 'order.status.updated';
    }

    public function broadcastWith(): array
    {
        return [
            'order_id' => $this->order->id,
            'order_number' => $this->order->order_number,
            'previous_status' => $this->previousStatus,
            'new_status' => $this->newStatus,
            'updated_at' => now()->toISOString(),
        ];
    }
}

Il frontend può ricevere questi eventi con Laravel Echo e aggiornare l'interfaccia utente di conseguenza.

javascript
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: true,
});

Echo.private(`orders.${userId}`)
    .listen('.order.status.updated', (event) => {
        console.log('Stato ordine cambiato:', event);
        updateOrderStatus(event.order_id, event.new_status);
    });

Event Subscribers per Workflow Complessi

Gli Event Subscribers permettono di raggruppare più handler di eventi in una singola classe. Questo è utile per logica specifica di dominio che deve reagire a diversi eventi.

php
<?php

namespace App\Listeners;

use App\Events\OrderPlaced;
use App\Events\OrderShipped;
use App\Events\OrderDelivered;
use App\Events\OrderCancelled;
use App\Services\NotificationService;
use Illuminate\Events\Dispatcher;

class OrderEventSubscriber
{
    public function __construct(
        private NotificationService $notifications
    ) {}

    public function handleOrderPlaced(OrderPlaced $event): void
    {
        $this->notifications->sendOrderConfirmation($event->order);
    }

    public function handleOrderShipped(OrderShipped $event): void
    {
        $this->notifications->sendShippingNotification(
            $event->order,
            $event->trackingNumber
        );
    }

    public function handleOrderDelivered(OrderDelivered $event): void
    {
        $this->notifications->sendDeliveryConfirmation($event->order);
        $this->notifications->requestReview($event->order);
    }

    public function handleOrderCancelled(OrderCancelled $event): void
    {
        $this->notifications->sendCancellationNotification(
            $event->order,
            $event->reason
        );
    }

    public function subscribe(Dispatcher $events): array
    {
        return [
            OrderPlaced::class => 'handleOrderPlaced',
            OrderShipped::class => 'handleOrderShipped',
            OrderDelivered::class => 'handleOrderDelivered',
            OrderCancelled::class => 'handleOrderCancelled',
        ];
    }
}

Il Subscriber viene registrato nell'EventServiceProvider e raggruppa logicamente tutti gli handler correlati.

php
protected $subscribe = [
    OrderEventSubscriber::class,
    PaymentEventSubscriber::class,
];

Pronto a superare i tuoi colloqui su Laravel?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Domande da Colloquio su Laravel Events

Domanda: Qual è la differenza tra Events e Observers in Laravel?

Gli Events sono messaggi generici che possono essere emessi ovunque nell'applicazione ed elaborati da qualsiasi Listener. Gli Observers sono progettati specificamente per i modelli Eloquent e reagiscono automaticamente alle operazioni CRUD. Gli Events offrono maggiore flessibilità, mentre gli Observers sono ottimizzati per logica specifica dei Model.

Domanda: Come si impedisce a un Listener di bloccare la propagazione degli eventi?

Se un Listener restituisce false, i Listeners successivi non vengono eseguiti. Per evitare questo comportamento, i Listeners dovrebbero restituire void o un altro valore. L'ordine dei Listeners nell'array determina l'ordine di esecuzione.

Domanda: Quando si dovrebbe usare ShouldBeUnique con Queued Listeners?

ShouldBeUnique impedisce che lo stesso job venga inserito più volte nella coda. Questo è importante per operazioni idempotenti come l'invio di email, dove i duplicati devono essere evitati.

php
class SendWelcomeEmail implements ShouldQueue, ShouldBeUnique
{
    public function uniqueId(): string
    {
        return $this->user->id;
    }
}

Domanda: Come si testa la logica basata su eventi?

Laravel fornisce Event::fake() per test isolati. Questo impedisce l'effettivo dispatch degli eventi e permette di effettuare assertions.

php
public function test_order_placement_dispatches_event(): void
{
    Event::fake([OrderPlaced::class]);

    $order = Order::factory()->create();

    Event::assertDispatched(OrderPlaced::class, function ($event) use ($order) {
        return $event->order->id === $order->id;
    });
}

Conclusione

Laravel Events e Listeners costituiscono un sistema potente per architetture applicative disaccoppiate e manutenibili. La combinazione di eventi sincroni, Queued Listeners e Broadcasting permette sia notifiche semplici che architetture Event-Driven complesse. I Model Observers semplificano la reazione alle modifiche del database, mentre gli Event Subscribers raggruppano handler correlati. Per i colloqui tecnici, una comprensione approfondita di questi concetti è essenziale, poiché l'architettura Event-Driven è diventata lo standard nelle applicazioni Laravel moderne.

Sfida del giorno

Sapresti trovare il bug in Laravel?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore di SharpSkill

Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.

Aggiornato il 20 agosto 2026

Tag

#laravel
#events
#listeners
#php
#event-driven

Condividi

Articoli correlati