Passer au contenu principal

Qu’est-ce qu’un événement de modèle

Les modèles Eloquent émettent automatiquement des événements aux différentes étapes de leur cycle de vie. En s’accrochant à ces événements, vous pouvez insérer des traitements avant et après les sauvegardes, suppressions, etc. Les événements émis par Eloquent sont les suivants.
ÉvénementMoment de déclenchement
retrievedLorsqu’un modèle est récupéré depuis la BDD
creatingJuste avant la sauvegarde d’un nouveau modèle
createdJuste après la sauvegarde d’un nouveau modèle
updatingJuste avant la mise à jour d’un modèle existant
updatedJuste après la mise à jour d’un modèle existant
savingJuste avant la sauvegarde (création ou mise à jour)
savedJuste après la sauvegarde (création ou mise à jour)
deletingJuste avant la suppression d’un modèle
deletedJuste après la suppression d’un modèle
trashedJuste après un soft delete
forceDeletingJuste avant une suppression physique
forceDeletedJuste après une suppression physique
restoringJuste avant la restauration d’un soft delete
restoredJuste après la restauration d’un soft delete
replicatingLors de l’appel à replicate()
Les événements terminant par -ing sont émis avant la persistance en BDD, ceux terminant par -ed sont émis après.
Lors des mass updates ou mass deletes (par exemple User::where(...)->update(...)), les événements saving, saved, updating, updated, deleting, deleted ne sont pas émis. Les modèles ne sont en effet pas réellement récupérés.

Écouteurs d’événements via closures

Pour traiter les événements simplement, vous pouvez enregistrer des closures dans la méthode booted du modèle.
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected static function booted(): void
    {
        static::created(function (User $user) {
            // Traitement à exécuter après la création de l'utilisateur
        });

        static::deleting(function (User $user) {
            // Traitement à exécuter avant la suppression de l'utilisateur
        });
    }
}
Pour exécuter le traitement en asynchrone via une queue, utilisez le helper queueable.
use function Illuminate\Events\queueable;

static::created(queueable(function (User $user) {
    // Exécuté en asynchrone via la queue
}));

Propriété $dispatchesEvents

Pour interagir avec le système d’événements de Laravel, mappez les événements du modèle sur des classes d’événements personnalisées via la propriété $dispatchesEvents.
<?php

namespace App\Models;

use App\Events\UserDeleted;
use App\Events\UserSaved;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    /**
     * Mapping des événements du modèle vers les classes d'événements
     *
     * @var array<string, string>
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}
Les classes d’événements mappées reçoivent l’instance du modèle dans leur constructeur.
<?php

namespace App\Events;

use App\Models\User;

class UserSaved
{
    public function __construct(
        public readonly User $user,
    ) {}
}

Création d’une classe Observer

Lorsqu’un même modèle doit traiter plusieurs événements, regrouper le tout dans une classe Observer est plus propre que d’aligner des closures.
1

Générer la classe avec Artisan

Générez le squelette avec la commande make:observer. L’option --model ajoute automatiquement les méthodes correspondant au modèle.
php artisan make:observer UserObserver --model=User
app/Observers/UserObserver.php est généré.
2

Implémenter les méthodes de chaque événement

Le nom de la méthode correspond au nom de l’événement. L’argument reçoit l’instance du modèle.
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    public function created(User $user): void
    {
        // Traitement après la création de l'utilisateur
    }

    public function updated(User $user): void
    {
        // Traitement après la mise à jour de l'utilisateur
    }

    public function deleted(User $user): void
    {
        // Traitement après la suppression de l'utilisateur
    }

    public function restored(User $user): void
    {
        // Traitement après la restauration d'un soft delete
    }

    public function forceDeleted(User $user): void
    {
        // Traitement après une suppression physique
    }
}
3

Enregistrer l'Observer sur le Model

Il existe deux méthodes d’enregistrement. Sous Laravel 13, l’utilisation de l’attribut #[ObservedBy] est recommandée.Méthode 1 : attribut #[ObservedBy] (recommandée)Il suffit d’appliquer l’attribut à la classe du modèle pour terminer l’enregistrement. Aucun changement dans AppServiceProvider n’est nécessaire.
<?php

namespace App\Models;

use App\Observers\UserObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Foundation\Auth\User as Authenticatable;

#[ObservedBy(UserObserver::class)]
class User extends Authenticatable
{
    //
}
Pour enregistrer plusieurs Observers, répétez l’attribut ou passez un tableau.
#[ObservedBy(UserObserver::class)]
#[ObservedBy(AuditObserver::class)]
class User extends Authenticatable
{
    //
}
Méthode 2 : enregistrement dans AppServiceProviderAppelez observe dans la méthode boot de AppServiceProvider.
<?php

namespace App\Providers;

use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        User::observe(UserObserver::class);
    }
}
L’attribut #[ObservedBy] se trouve dans le namespace Illuminate\Database\Eloquent\Attributes. C’est une syntaxe native PHP 8.0+ activement adoptée dans Laravel 13.

Observers dans les transactions BDD

Lorsqu’un modèle est créé ou mis à jour dans une transaction, il est parfois souhaitable d’exécuter l’Observer après le commit de la transaction. Implémentez l’interface ShouldHandleEventsAfterCommit pour obtenir ce comportement.
<?php

namespace App\Observers;

use App\Models\User;
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;

class UserObserver implements ShouldHandleEventsAfterCommit
{
    public function created(User $user): void
    {
        // Exécuté après le commit de la transaction
    }
}
En dehors d’une transaction, l’exécution est immédiate comme d’habitude.

Désactiver temporairement les événements

withoutEvents pour désactiver les événements sur un traitement précis

Dans la closure passée à User::withoutEvents(), aucun événement de modèle n’est émis.
use App\Models\User;

$user = User::withoutEvents(function () {
    User::findOrFail(1)->delete();

    return User::find(2);
});

saveQuietly pour désactiver les événements à la sauvegarde

Pour sauvegarder sans émettre d’événement, utilisez saveQuietly.
$user = User::findOrFail(1);

$user->name = 'Victoria Faith';

$user->saveQuietly();
Des méthodes similaires existent pour la suppression, la restauration et la réplication.
$user->deleteQuietly();
$user->restoreQuietly();

Cas d’usage pratiques

Nettoyage automatique du cache

Lorsqu’un modèle est mis à jour ou supprimé, nettoyez automatiquement le cache associé.
<?php

namespace App\Observers;

use App\Models\Post;
use Illuminate\Support\Facades\Cache;

class PostObserver
{
    public function saved(Post $post): void
    {
        Cache::forget("post:{$post->id}");
        Cache::forget('posts:latest');
    }

    public function deleted(Post $post): void
    {
        Cache::forget("post:{$post->id}");
        Cache::forget('posts:latest');
    }
}

Journal d’audit

Consignez automatiquement l’historique des modifications d’un modèle. getDirty() permet de récupérer les valeurs modifiées.
<?php

namespace App\Observers;

use App\Models\AuditLog;
use App\Models\User;

class UserObserver
{
    public function updating(User $user): void
    {
        AuditLog::create([
            'model_type' => User::class,
            'model_id'   => $user->id,
            'changes'    => $user->getDirty(),
            'user_id'    => auth()->id(),
        ]);
    }

    public function deleted(User $user): void
    {
        AuditLog::create([
            'model_type' => User::class,
            'model_id'   => $user->id,
            'changes'    => ['deleted' => true],
            'user_id'    => auth()->id(),
        ]);
    }
}
L’événement updating est émis avant la sauvegarde en BDD, donc getDirty() retourne les valeurs sur le point d’être modifiées. Appelé après l’événement updated, getDirty() sera vide.

Mise à jour automatique de modèles associés

Exemple de mise à jour automatique des stocks à la finalisation d’une commande.
<?php

namespace App\Observers;

use App\Models\Order;

class OrderObserver
{
    public function created(Order $order): void
    {
        foreach ($order->items as $item) {
            $item->product->decrement('stock', $item->quantity);
        }
    }

    public function deleted(Order $order): void
    {
        foreach ($order->items as $item) {
            $item->product->increment('stock', $item->quantity);
        }
    }
}

Étapes suivantes

Avancé : attributs PHP

Faites un tour d’ensemble des attributs PHP dans Laravel 13, y compris #[ObservedBy].
Dernière modification le 13 juillet 2026