Eventi

Introduzione

Gli eventi di Laravel offrono un’implementazione semplice del pattern observer, permettendoti di iscriverti e ascoltare vari eventi che si verificano all’interno della tua applicazione. Le classi degli eventi sono solitamente memorizzate nella directory app/Events, mentre i loro listener si trovano in app/Listeners. Non preoccuparti se non vedi queste directory nella tua applicazione, poiché verranno create automaticamente quando generi eventi e listener usando i comandi della console Artisan.

Gli eventi sono un ottimo modo per disaccoppiare vari aspetti della tua applicazione, poiché un singolo evento può avere più listener che non dipendono l’uno dall’altro. Ad esempio, potresti voler inviare una notifica su Slack al tuo utente ogni volta che un ordine viene spedito. Invece di collegare il codice di elaborazione degli ordini al codice della notifica su Slack, puoi generare un evento App\Events\OrderShipped che un listener può ricevere e utilizzare per inviare una notifica su Slack.

Generare Eventi e Listener

Per generare rapidamente eventi e listener, puoi usare i comandi Artisan make:event e make:listener:

php artisan make:event PodcastProcessed

php artisan make:listener SendPodcastNotification --event=PodcastProcessed

Per comodità, puoi anche eseguire i comandi Artisan make:event e make:listener senza argomenti aggiuntivi. In questo modo, Laravel ti chiederà automaticamente il nome della classe e, quando crei un listener, l’evento a cui deve ascoltare:

php artisan make:event

php artisan make:listener

Registrazione di Eventi e Listener

Scoperta degli Eventi

Per impostazione predefinita, Laravel trova e registra automaticamente i tuoi event listener scansionando la directory Listeners della tua applicazione. Quando Laravel trova un metodo di una classe listener che inizia con handle o __invoke, registrerà quei metodi come listener per l’evento indicato nel tipo di parametro nella firma del metodo:

    use App\Events\PodcastProcessed;

    class SendPodcastNotification
    {
        /**
         * Gestisce l'evento specificato.
         */
        public function handle(PodcastProcessed $event): void
        {
            // ...
        }
    }

Puoi ascoltare più eventi usando i tipi unione di PHP:

    /**
     * Gestisce l'evento specificato.
     */
    public function handle(PodcastProcessed|PodcastPublished $event): void
    {
        // ...
    }

Se prevedi di memorizzare i tuoi listener in una directory diversa o in più directory, puoi dire a Laravel di scansionare quelle directory usando il metodo withEvents nel file bootstrap/app.php della tua applicazione:

    ->withEvents(discover: [
        __DIR__.'/../app/Domain/Orders/Listeners',
    ])

Il comando event:list può essere usato per elencare tutti i listener registrati nella tua applicazione:

php artisan event:list

Scoperta degli Eventi in Produzione

Per aumentare la velocità della tua applicazione, dovresti memorizzare nella cache un manifesto di tutti i listener della tua applicazione usando i comandi Artisan optimize o event:cache. Di solito, questo comando dovrebbe essere eseguito come parte del processo di distribuzione della tua applicazione. Questo manifesto verrà utilizzato dal framework per velocizzare il processo di registrazione degli eventi. Il comando event:clear può essere usato per eliminare la cache degli eventi.

Registrazione Manuale degli Eventi

Utilizzando il facade Event, puoi registrare manualmente gli eventi e i relativi listener all’interno del metodo boot del AppServiceProvider della tua applicazione:

use App\Domain\Orders\Events\PodcastProcessed;
use App\Domain\Orders\Listeners\SendPodcastNotification;
use Illuminate\Support\Facades\Event;

/**
 * Inizializza i servizi dell'applicazione.
 */
public function boot(): void
{
    Event::listen(
        PodcastProcessed::class,
        SendPodcastNotification::class,
    );
}

Il comando event:list può essere utilizzato per elencare tutti i listener registrati nella tua applicazione:

php artisan event:list

Listener con Closure

Di solito, i listener sono definiti come classi; tuttavia, puoi anche registrare manualmente listener di eventi basati su closure nel metodo boot dell’AppServiceProvider della tua applicazione:

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

/**
 * Avvia i servizi dell'applicazione.
 */
public function boot(): void
{
    Event::listen(function (PodcastProcessed $event) {
        // ...
    });
}

Listener Anonimi in Coda

Quando registri listener di eventi basati su closure, puoi racchiudere la closure del listener all’interno della funzione Illuminate\Events\queueable per istruire Laravel ad eseguire il listener utilizzando il sistema delle code:

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Event::listen(queueable(function (PodcastProcessed $event) {
        // ...
    }));
}

Come i job in coda, puoi usare i metodi onConnection, onQueue e delay per personalizzare l’esecuzione del listener in coda:

Event::listen(queueable(function (PodcastProcessed $event) {
    // ...
})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));

Se desideri gestire i fallimenti dei listener anonimi in coda, puoi fornire una closure al metodo catch durante la definizione del listener queueable. Questa closure riceverà l’istanza dell’evento e l’istanza di Throwable che ha causato il fallimento del listener:

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
use Throwable;

Event::listen(queueable(function (PodcastProcessed $event) {
    // ...
})->catch(function (PodcastProcessed $event, Throwable $e) {
    // Il listener in coda è fallito...
}));

Listener con carattere jolly

Puoi anche registrare listener usando il carattere * come parametro jolly, permettendoti di catturare più eventi con lo stesso listener. I listener con carattere jolly ricevono il nome dell’evento come primo argomento e l’intero array dei dati dell’evento come secondo argomento:

    Event::listen('event.*', function (string $eventName, array $data) {
        // ...
    });

Definire gli Eventi

Una classe di evento è fondamentalmente un contenitore di dati che tiene le informazioni relative all’evento. Ad esempio, supponiamo che un evento App\Events\OrderShipped riceva un oggetto Eloquent ORM:

<?php

namespace App\Events;

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

class OrderShipped
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Crea una nuova istanza dell'evento.
     */
    public function __construct(
        public Order $order,
    ) {}
}

Come puoi vedere, questa classe di evento non contiene logica. È un contenitore per l’istanza App\Models\Order che è stata acquistata. Il trait SerializesModels utilizzato dall’evento serializzerà correttamente qualsiasi modello Eloquent se l’oggetto evento viene serializzato usando la funzione serialize di PHP, ad esempio quando si utilizzano listener in coda.

Definizione dei Listener

Successivamente, diamo un’occhiata al listener per il nostro evento di esempio. I listener degli eventi ricevono le istanze degli eventi nel loro metodo handle. Il comando Artisan make:listener, quando viene eseguito con l’opzione --event, importa automaticamente la classe dell’evento corretta e specifica il tipo di evento nel metodo handle. All’interno del metodo handle, puoi eseguire tutte le azioni necessarie per rispondere all’evento:

<?php

namespace App\Listeners;

use App\Events\OrderShipped;

class SendShipmentNotification
{
    /**
     * Crea il listener dell'evento.
     */
    public function __construct() {}

    /**
     * Gestisce l'evento.
     */
    public function handle(OrderShipped $event): void
    {
        // Accedi all'ordine usando $event->order...
    }
}

I tuoi listener degli eventi possono anche specificare il tipo di eventuali dipendenze di cui hanno bisogno nei loro costruttori. Tutti i listener degli eventi sono risolti tramite il service container di Laravel, quindi le dipendenze verranno iniettate automaticamente.

Fermare la Propagazione di un Evento

A volte, potresti voler fermare la propagazione di un evento ad altri listener. Puoi farlo restituendo false dal metodo handle del tuo listener.

Listener di Eventi in Coda

Mettere in coda i listener può essere vantaggioso se il tuo listener deve eseguire un’attività più "lenta" del solito, come inviare un’email o effettuare una richiesta HTTP. Prima di utilizzare listener in coda, assicurati di configurare la tua coda e avviare un worker della coda sul tuo server o nell’ambiente di sviluppo locale.

Per specificare che un listener deve essere messo in coda, aggiungi l’interfaccia ShouldQueue alla classe del listener. I listener generati dai comandi make:listener di Artisan hanno già questa interfaccia importata nello spazio dei nomi corrente, quindi puoi usarla subito:

<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    // ...
}

E tutto qui! Ora, quando un evento gestito da questo listener viene dispatchato, il listener sarà automaticamente messo in coda dall’event dispatcher utilizzando il sistema di coda di Laravel. Se non vengono generate eccezioni quando il listener viene eseguito dalla coda, il job in coda sarà automaticamente eliminato dopo aver finito l’elaborazione.

Personalizzare la Connessione della Queue, il Nome e il Ritardo

Se desideri personalizzare la connessione della queue, il nome della queue o il tempo di ritardo di un event listener, puoi definire le proprietà $connection, $queue o $delay nella tua classe listener:

<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    /**
     * Il nome della connessione a cui il job deve essere inviato.
     *
     * @var string|null
     */
    public $connection = 'sqs';

    /**
     * Il nome della queue a cui il job deve essere inviato.
     *
     * @var string|null
     */
    public $queue = 'listeners';

    /**
     * Il tempo (secondi) prima che il job venga elaborato.
     *
     * @var int
     */
    public $delay = 60;
}

Se desideri definire la connessione della queue del listener, il nome della queue o il ritardo a runtime, puoi definire i metodi viaConnection, viaQueue o withDelay nel listener:

/**
 * Ottieni il nome della connessione della queue del listener.
 */
public function viaConnection(): string
{
    return 'sqs';
}

/**
 * Ottieni il nome della queue del listener.
 */
public function viaQueue(): string
{
    return 'listeners';
}

/**
 * Ottieni il numero di secondi prima che il job venga elaborato.
 */
public function withDelay(OrderShipped $event): int
{
    return $event->highPriority ? 0 : 60;
}

Mettere in Coda i Listener a Condizioni Specifiche

A volte, potrebbe essere necessario determinare se un listener debba essere accodato in base ad alcuni dati disponibili solo a runtime. Per fare ciò, è possibile aggiungere un metodo shouldQueue a un listener per decidere se accodarlo. Se il metodo shouldQueue restituisce false, il listener non sarà accodato:

<?php

namespace App\Listeners;

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

class RewardGiftCard implements ShouldQueue
{
    /**
     * Reward a gift card to the customer.
     */
    public function handle(OrderCreated $event): void
    {
        // ...
    }

    /**
     * Determine whether the listener should be queued.
     */
    public function shouldQueue(OrderCreated $event): bool
    {
        return $event->order->subtotal >= 5000;
    }
}

Interagire Manualmente con la Queue

Se hai bisogno di accedere manualmente ai metodi delete e release del job sottostante della coda del listener, puoi farlo utilizzando il trait Illuminate\Queue\InteractsWithQueue. Questo trait viene importato di default nei listener generati e fornisce accesso a questi metodi:

<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Gestisci l'evento.
     */
    public function handle(OrderShipped $event): void
    {
        if (true) {
            $this->release(30);
        }
    }
}

Listener di Eventi in Coda e Transazioni del Database

Quando i listener in coda vengono eseguiti all’interno di transazioni del database, potrebbero essere gestiti dalla coda prima che la transazione sia confermata. In tal caso, eventuali aggiornamenti apportati ai modelli o ai record del database durante la transazione potrebbero non essere ancora presenti nel database. Inoltre, i modelli o i record creati nella transazione potrebbero non esistere nel database. Se il tuo listener dipende da questi modelli, potrebbero verificarsi errori imprevisti quando il job che dispatcha il listener in coda viene elaborato.

Se l’opzione di configurazione after_commit della tua connessione di coda è impostata su false, puoi comunque indicare che un particolare listener in coda debba essere eseguito dopo che tutte le transazioni del database aperte sono state confermate, implementando l’interfaccia ShouldQueueAfterCommit nella classe del listener:

    <?php

    namespace App\Listeners;

    use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
    use Illuminate\Queue\InteractsWithQueue;

    class SendShipmentNotification implements ShouldQueueAfterCommit
    {
        use InteractsWithQueue;
    }

Per saperne di più su come gestire questi problemi, consulta la documentazione relativa a queued jobs e transazioni del database.

Gestione del Fallimento di Job in Coda

A volte i tuoi listener di eventi in coda possono fallire. Se il listener in coda supera il numero massimo di tentativi come definito dal tuo queue worker, il metodo failed verrà chiamato sul tuo listener. Il metodo failed riceve l’istanza dell’evento e il Throwable che ha causato il fallimento:

<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Handle the event.
     */
    public function handle(OrderShipped $event): void
    {
        // ...
    }

    /**
     * Handle a job failure.
     */
    public function failed(OrderShipped $event, Throwable $exception): void
    {
        // ...
    }
}

Specificare il Numero Massimo di Tentativi per un Listener in Coda

Se uno dei tuoi listener in coda incontra un errore, probabilmente non vuoi che continui a tentare ripetutamente senza fine. Per questo, Laravel offre diverse modalità per specificare quante volte o per quanto tempo un listener può essere tentato.

Puoi definire una proprietà $tries nella tua classe listener per specificare quante volte il listener può essere provato prima di considerarlo fallito:

<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Il numero di volte che il listener in coda può essere tentato.
     *
     * @var int
     */
    public $tries = 5;
}

In alternativa a definire quante volte un listener può essere tentato prima di fallire, puoi definire un tempo oltre il quale il listener non sarà più tentato. Questo permette di provare un listener un numero qualsiasi di volte entro un determinato lasso di tempo. Per definire il momento in cui un listener non deve più essere tentato, aggiungi un metodo retryUntil alla tua classe listener. Questo metodo deve restituire un’istanza di DateTime:

use DateTime;

/**
 * Determina il momento in cui il listener deve scadere.
 */
public function retryUntil(): DateTime
{
    return now()->addMinutes(5);
}

Specificare il Backoff del Listener in Coda

Se desideri configurare quanti secondi Laravel dovrebbe attendere prima di tentare nuovamente un listener che ha incontrato un’eccezione, puoi farlo definendo una proprietà backoff nella tua classe listener:

/**
 * Il numero di secondi da attendere prima di riprovare il listener in coda.
 *
 * @var int
 */
public $backoff = 3;

Se hai bisogno di una logica più complessa per determinare il tempo di backoff del listener, puoi definire un metodo backoff nella tua classe listener:

/**
 * Calcola il numero di secondi da attendere prima di riprovare il listener in coda.
 */
public function backoff(): int
{
    return 3;
}

Puoi facilmente configurare dei backoff "esponenziali" restituendo un array di valori di backoff dal metodo backoff. In questo esempio, il ritardo del retry sarà di 1 secondo per il primo tentativo, 5 secondi per il secondo tentativo, 10 secondi per il terzo tentativo, e 10 secondi per ogni retry successivo se ci sono altri tentativi rimanenti:

/**
 * Calcola il numero di secondi da attendere prima di riprovare il listener in coda.
 *
 * @return array<int, int>
 */
public function backoff(): array
{
    return [1, 5, 10];
}

Invio degli Eventi

Per inviare un evento, puoi chiamare il metodo statico dispatch sull’evento. Questo metodo è reso disponibile sull’evento tramite il trait Illuminate\Foundation\Events\Dispatchable. Qualsiasi argomento passato al metodo dispatch verrà passato al costruttore dell’evento:

<?php

namespace App\Http\Controllers;

use App\Events\OrderShipped;
use App\Http\Controllers\Controller;
use App\Models\Order;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class OrderShipmentController extends Controller
{
    /**
     * Spedisci l'ordine dato.
     */
    public function store(Request $request): RedirectResponse
    {
        $order = Order::findOrFail($request->order_id);

        // Logica di spedizione dell'ordine...

        OrderShipped::dispatch($order);

        return redirect('/orders');
    }
}

Se desideri inviare un evento condizionatamente, puoi usare i metodi dispatchIf e dispatchUnless:

OrderShipped::dispatchIf($condition, $order);

OrderShipped::dispatchUnless($condition, $order);

Durante i test, può essere utile verificare che determinati eventi siano stati inviati senza realmente attivare i loro listener. Gli helper di test integrati di Laravel semplificano questo compito.

Invio di Eventi Dopo le Transazioni di Database

A volte potresti voler istruire Laravel a inviare un evento solo dopo che la transazione di database attiva è stata confermata. Per fare ciò, puoi implementare l’interfaccia ShouldDispatchAfterCommit nella classe dell’evento.

Questa interfaccia indica a Laravel di non inviare l’evento fino a quando la transazione di database corrente non è stata confermata. Se la transazione fallisce, l’evento verrà scartato. Se non c’è alcuna transazione di database in corso quando l’evento viene inviato, l’evento verrà inviato immediatamente:

<?php

namespace App\Events;

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

class OrderShipped implements ShouldDispatchAfterCommit
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Crea una nuova istanza dell'evento.
     */
    public function __construct(
        public Order $order,
    ) {}
}

Sottoscrittori di Eventi

Scrivere Subscriber di Eventi

I subscriber di eventi sono classi che possono iscriversi a più eventi direttamente all’interno della classe subscriber, permettendo di definire diversi gestori di eventi in un’unica classe. I subscriber devono definire un metodo subscribe, al quale verrà passata un’istanza di event dispatcher. Puoi chiamare il metodo listen sul dispatcher fornito per registrare i listener degli eventi:

<?php

namespace App\Listeners;

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

class UserEventSubscriber
{
    /**
     * Gestisce gli eventi di login dell'utente.
     */
    public function handleUserLogin(Login $event): void {}

    /**
     * Gestisce gli eventi di logout dell'utente.
     */
    public function handleUserLogout(Logout $event): void {}

    /**
     * Registra i listener per il subscriber.
     */
    public function subscribe(Dispatcher $events): void
    {
        $events->listen(
            Login::class,
            [UserEventSubscriber::class, 'handleUserLogin']
        );

        $events->listen(
            Logout::class,
            [UserEventSubscriber::class, 'handleUserLogout']
        );
    }
}

Se i metodi listener degli eventi sono definiti all’interno del subscriber stesso, potresti trovare più comodo restituire un array di eventi e nomi di metodi dal metodo subscribe del subscriber. Laravel determinerà automaticamente il nome della classe del subscriber durante la registrazione dei listener degli eventi:

<?php

namespace App\Listeners;

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

class UserEventSubscriber
{
    /**
     * Gestisce gli eventi di login dell'utente.
     */
    public function handleUserLogin(Login $event): void {}

    /**
     * Gestisce gli eventi di logout dell'utente.
     */
    public function handleUserLogout(Logout $event): void {}

    /**
     * Registra i listener per il subscriber.
     *
     * @return array<string, string>
     */
    public function subscribe(Dispatcher $events): array
    {
        return [
            Login::class => 'handleUserLogin',
            Logout::class => 'handleUserLogout',
        ];
    }
}

Registrare gli Event Subscribers

Dopo aver creato lo subscriber, Laravel registrerà automaticamente i metodi gestori all’interno dello subscriber se seguono le convenzioni di scoperta eventi di Laravel. Altrimenti, puoi registrare manualmente il tuo subscriber utilizzando il metodo subscribe della facade Event. Di solito, questo va fatto nel metodo boot dell’AppServiceProvider della tua applicazione:

<?php

namespace App\Providers;

use App\Listeners\UserEventSubscriber;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Event::subscribe(UserEventSubscriber::class);
    }
}

Testing

Quando testi del codice che invia eventi, potresti voler istruire Laravel a non eseguire effettivamente i listener dell’evento, poiché il codice del listener può essere testato direttamente e separatamente dal codice che invia l’evento corrispondente. Naturalmente, per testare il listener stesso, puoi istanziare un’istanza del listener e invocare direttamente il metodo handle nel tuo test.

Utilizzando il metodo fake della facade Event, puoi impedire l’esecuzione dei listener, eseguire il codice in prova e poi verificare quali eventi sono stati inviati dalla tua applicazione usando i metodi assertDispatched, assertNotDispatched e assertNothingDispatched:

<?php

use App\Events\OrderFailedToShip;
use App\Events\OrderShipped;
use Illuminate\Support\Facades\Event;

test('orders can be shipped', function () {
    Event::fake();

    // Esegui la spedizione dell'ordine...

    // Verifica che un evento sia stato inviato...
    Event::assertDispatched(OrderShipped::class);

    // Verifica che un evento sia stato inviato due volte...
    Event::assertDispatched(OrderShipped::class, 2);

    // Verifica che un evento non sia stato inviato...
    Event::assertNotDispatched(OrderFailedToShip::class);

    // Verifica che nessun evento sia stato inviato...
    Event::assertNothingDispatched();
});
<?php

namespace Tests\Feature;

use App\Events\OrderFailedToShip;
use App\Events\OrderShipped;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * Testa la spedizione dell'ordine.
     */
    public function test_orders_can_be_shipped(): void
    {
        Event::fake();

        // Esegui la spedizione dell'ordine...

        // Verifica che un evento sia stato inviato...
        Event::assertDispatched(OrderShipped::class);

        // Verifica che un evento sia stato inviato due volte...
        Event::assertDispatched(OrderShipped::class, 2);

        // Verifica che un evento non sia stato inviato...
        Event::assertNotDispatched(OrderFailedToShip::class);

        // Verifica che nessun evento sia stato inviato...
        Event::assertNothingDispatched();
    }
}

Puoi passare una closure ai metodi assertDispatched o assertNotDispatched per verificare che un evento sia stato inviato e che superi un determinato "test di verità". Se almeno un evento viene inviato e supera il test di verità dato, l’asserzione avrà successo:

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

Se desideri semplicemente verificare che un listener di eventi stia ascoltando un determinato evento, puoi usare il metodo assertListening:

Event::assertListening(
    OrderShipped::class,
    SendShipmentNotification::class
);

Dopo aver chiamato Event::fake(), nessun listener di eventi verrà eseguito. Quindi, se i tuoi test utilizzano factory di modelli che si basano sugli eventi, come la creazione di un UUID durante l’evento creating di un modello, dovresti chiamare Event::fake() dopo aver utilizzato le tue factory.

Simulare un Sottoinsieme di Eventi

Se desideri simulare i listener degli eventi solo per un insieme specifico di eventi, puoi passarli al metodo fake o fakeFor:

test('orders can be processed', function () {
    Event::fake([
        OrderCreated::class,
    ]);

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

    Event::assertDispatched(OrderCreated::class);

    // Altri eventi vengono dispatchati normalmente...
    $order->update([...]);
});
/**
 * Test del processo d'ordine.
 */
public function test_orders_can_be_processed(): void
{
    Event::fake([
        OrderCreated::class,
    ]);

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

    Event::assertDispatched(OrderCreated::class);

    // Altri eventi vengono dispatchati normalmente...
    $order->update([...]);
}

Puoi simulare tutti gli eventi tranne un insieme di eventi specificati usando il metodo except:

    Event::fake()->except([
        OrderCreated::class,
    ]);

Falsi Eventi con Ambito

Se desideri falsificare solo i listener degli eventi per una parte del tuo test, puoi usare il metodo fakeFor:

<?php

use App\Events\OrderCreated;
use App\Models\Order;
use Illuminate\Support\Facades\Event;

test('orders can be processed', function () {
    $order = Event::fakeFor(function () {
        $order = Order::factory()->create();

        Event::assertDispatched(OrderCreated::class);

        return $order;
    });

    // Gli eventi vengono dispatchati normalmente e gli osservatori verranno eseguiti...
    $order->update([...]);
});
<?php

namespace Tests\Feature;

use App\Events\OrderCreated;
use App\Models\Order;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * Test del processo d'ordine.
     */
    public function test_orders_can_be_processed(): void
    {
        $order = Event::fakeFor(function () {
            $order = Order::factory()->create();

            Event::assertDispatched(OrderCreated::class);

            return $order;
        });

        // Gli eventi vengono dispatchati normalmente e gli osservatori verranno eseguiti...
        $order->update([...]);
    }
}
Lascia un commento

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *