Laravel 12.51 : Callbacks afterSending, Validator fluent et timeout MySQL
Laravel 12.51, sortie le 10 février 2026, enrichit le framework avec des fonctionnalités qui simplifient le quotidien des développeurs. Callbacks post-envoi de notifications, validation fluide, timeout MySQL par requête et évaluation paresseuse dans firstOrCreate : cette release cible directement la productivité.
Contexte de cette release
Laravel 12.51 s’inscrit dans le cycle hebdomadaire de releases mineures de Laravel 12. Avec plus de 50 pull requests mergées, cette version se concentre sur l’expérience développeur tout en corrigeant plusieurs bugs importants sur Eloquent, les queues et le système de traduction.
Callbacks afterSending sur les notifications
Jusqu’ici, pour exécuter une action après l’envoi d’une notification, vous deviez écouter l’événement NotificationSent. Laravel 12.51 simplifie ce workflow avec la méthode afterSending directement dans la classe de notification.
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class ReservationConfirmee extends Notification
{
public function __construct(
public Reservation $reservation
) {}
public function via(): array
{
return ['mail'];
}
public function toMail(): MailMessage
{
return (new MailMessage)
->subject('Réservation confirmée')
->line('Votre réservation a bien été enregistrée.');
}
// Exécuté automatiquement après l'envoi
public function afterSending($notifiable, $channel, $response)
{
$this->reservation->update(['notifie_le' => now()]);
}
}
La méthode reçoit trois paramètres : l’entité notifiable, le canal utilisé et la réponse du canal. Plus besoin de créer un listener dédié pour une logique post-envoi simple.
Méthodes whenFails et whenPasses sur le Validator
Le Validator gagne deux nouvelles méthodes fluides : whenFails() et whenPasses(). Leur intérêt principal ? La validation en dehors du cycle HTTP classique — commandes Artisan, jobs de queue, services applicatifs.
use Illuminate\Support\Facades\Validator;
public function traiterFichier($fichier): void
{
Validator::make(
['fichier' => $fichier],
['fichier' => 'required|image|dimensions:min_width=100,min_height=200']
)->whenFails(function ($validator) {
// Lancer une exception si la validation échoue
throw new \InvalidArgumentException(
'Fichier invalide : ' . $validator->errors()->first()
);
})->whenPasses(function () use ($fichier) {
// Traiter le fichier uniquement si valide
Storage::put('uploads/' . $fichier->hashName(), $fichier);
});
}
Ces méthodes remplacent avantageusement le pattern classique if ($validator->fails()) { ... } et rendent le code plus lisible grâce au chaînage fluide.
Timeout MySQL par requête
Laravel 12.51 introduit la méthode timeout() sur le query builder. Elle génère un hint d’optimiseur MySQL MAX_EXECUTION_TIME pour limiter le temps d’exécution d’une requête donnée.
use App\Models\Commande;
// Timeout de 30 secondes sur cette requête spécifique
$commandes = Commande::query()
->where('statut', 'en_attente')
->where('created_at', '<', now()->subDays(30))
->timeout(30)
->get();
// SQL généré :
// SELECT /*+ MAX_EXECUTION_TIME(30000) */ * FROM `commandes`
// WHERE `statut` = ? AND `created_at` < ?
Vous pouvez aussi appliquer un timeout global via un scope Eloquent :
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
class TimeoutScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
// Timeout de 60 secondes par défaut
$builder->timeout(60);
}
}
#[ScopedBy([TimeoutScope::class])]
class Rapport extends Model
{
// Toutes les requêtes sur ce modèle auront un timeout de 60s
}
Cette fonctionnalité est exclusivement MySQL. Le timeout est exprimé en secondes et converti automatiquement en millisecondes dans le hint SQL.
Évaluation paresseuse dans firstOrCreate et createOrFirst
Les méthodes firstOrCreate et createOrFirst acceptent désormais des closures pour le paramètre $values. Le code coûteux (appels API, géocodage, calculs lourds) ne s’exécute que si un nouveau record doit être créé.
use App\Models\Adresse;
use App\Services\Geocodeur;
// Avant : le géocodage s'exécute systématiquement
$adresse = Adresse::firstOrCreate(
['rue' => $donneesRue],
['coordonnees' => Geocodeur::resoudre($donneesRue)] // Appel API inutile si existant
);
// Après : le géocodage ne s'exécute que si nécessaire
$adresse = Adresse::firstOrCreate(
['rue' => $donneesRue],
fn () => ['coordonnees' => Geocodeur::resoudre($donneesRue)]
);
Si l’enregistrement existe déjà, la closure n’est jamais évaluée. Sur des opérations coûteuses comme des appels à des API tierces, le gain de performance peut être significatif.
Autres nouveautés notables
Événement BatchCancelled
Un nouvel événement Illuminate\Bus\Events\BatchCancelled est dispatché quand un batch est annulé, que ce soit manuellement ou suite à l’échec d’un job. Fini le polling :
use Illuminate\Bus\Events\BatchCancelled;
use Illuminate\Support\Facades\Event;
Event::listen(BatchCancelled::class, function (BatchCancelled $event) {
Log::warning("Batch {$event->batch->id} annulé.");
});
Builders Eloquent comme sous-requêtes dans les updates
Plus besoin d’appeler ->toBase() pour utiliser un builder Eloquent comme sous-requête dans un update() :
// Plus besoin de ->toBase()
Produit::where('categorie_id', 5)->update([
'prix_moyen' => Statistique::where('type', 'prix')->select('valeur'),
]);
Méthode withoutHeader sur les réponses
Supprimez un ou plusieurs headers d’une réponse HTTP :
return response($contenu)
->withoutHeader(['X-Debug', 'X-Powered-By', 'Server']);
Points d’attention
- La méthode
timeout()fonctionne uniquement avec MySQL. Les autres SGBD ignoreront ce hint. afterSendingest exécuté pour chaque canal de notification. Si vous envoyez viamailetdatabase, le callback sera appelé deux fois.Request::get()est désormais marqué comme deprecated en faveur deRequest::input()— pensez à mettre à jour votre code.- Le timeout MySQL est exprimé en secondes dans l’API Laravel, mais converti en millisecondes dans le SQL généré.
Mise à jour
Pour mettre à jour vers Laravel 12.51 :
composer update laravel/framework
Laravel 12.51 ne contient aucun breaking change. La mise à jour depuis n’importe quelle version 12.x est transparente.
Ressources
À propos de Laravel Actu
Développeur passionné par Laravel et son écosystème.
Voir tous les articles