Hire Laravel developers with AI expertise at $20/hr. Get started in 48 hours.

Laravel 12.51.0 Adds afterSending Callbacks, Validator whenFails, and MySQL Timeout

Published on by

Laravel 12.51.0 Adds afterSending Callbacks, Validator whenFails, and MySQL Timeout image

Release Date: February 10, 2026
Laravel Version: 12.51.0

Summary

Laravel v12.51.0 adds notification afterSending() callbacks, fluent whenFails() and whenPasses() methods on the Validator, a MySQL query builder timeout() method, and closure support in firstOrCreate and createOrFirst for lazy value evaluation. This release also introduces a BatchCancelled event, support for Eloquent builders as subqueries in update queries, and a withoutHeader() method on responses.

Key highlights include:

  • Notification afterSending() callbacks
  • Validator whenFails() and whenPasses() methods
  • MySQL query builder timeout() method
  • Closure support in firstOrCreate / createOrFirst
  • BatchCancelled event
  • Eloquent builders as subqueries in update queries
  • withoutHeader() on Response
  • Batch testing improvements and cache isolation for parallel tests
  • Numerous bug fixes and type improvements

What's New

Notification afterSending() Callbacks

Notification classes can now define an afterSending method that runs after the notification is sent on each channel. This provides a convenient way to handle post-send logic — like updating a model or firing an event — without registering a dedicated NotificationSent listener:

class BookingNotification extends Notification
{
public function __construct(public Booking $booking) {}
 
public function via(): array
{
return ['mail'];
}
 
public function toMail(): MailMessage
{
// ...
}
 
public function afterSending($notifiable, $channel, $response)
{
$this->booking->update(['notified_at' => now()]);
}
}

The method receives the notifiable instance, the channel name, and the channel's response, giving you full context for any follow-up actions.

Pull Request: #58654

Validator whenFails() and whenPasses() Methods

The Validator now includes fluent whenFails() and whenPasses() methods for handling validation results, which is particularly useful outside the HTTP request cycle — such as in Artisan commands or queue jobs:

public function someMethod($file)
{
Validator::make(
['file' => $file],
['file' => 'required|image|dimensions:min_width=100,min_height=200']
)->whenFails(function () {
throw new InvalidArgumentException('Provided file is invalid');
});
}

These methods provide an alternative to manually checking $validator->fails() or wrapping validation in try/catch blocks.

Pull Request: #58655

MySQL Query Builder timeout() Method

A new timeout() method on the query builder sets a per-query execution timeout for MySQL using the MAX_EXECUTION_TIME optimizer hint:

Student::query()
->where('email', 'like', '%text%')
->timeout(60)
->get();
 
// Generates: select /*+ MAX_EXECUTION_TIME(60000) */ * from `students` where `email` like ?

You can also apply it as a default via a global scope:

use Illuminate\Database\Eloquent\Attributes\ScopedBy;
 
class TimeoutScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->timeout(60);
}
}
 
#[ScopedBy([TimeoutScope::class])]
class User extends Model
{
// ...
}

This is MySQL-specific and accepts a timeout value in seconds.

Pull Request: #58644

Closures in firstOrCreate and createOrFirst

The firstOrCreate and createOrFirst methods now accept closures for the $values parameter, enabling lazy evaluation of expensive operations:

// Before — expensive operation always runs
$location = Location::query()->firstWhere('address', $address);
 
if ($location) {
return $location;
}
 
return Location::create([
'address' => $address,
'coordinates' => Geocoder::resolve($address),
]);
 
// After — geocoding only runs when a new record is needed
$location = Location::firstOrCreate(
['address' => $address],
fn () => ['coordinates' => Geocoder::resolve($address)],
);

When the record already exists, the closure is never evaluated, avoiding unnecessary API calls, computations, or other expensive work.

Pull Request: #58639

BatchCancelled Event

A new BatchCancelled event fires globally when a batch is cancelled, whether automatically due to a job failure or through a manual cancellation call. This lets you listen for batch cancellations across your application without polling:

use Illuminate\Bus\Events\BatchCancelled;
use Illuminate\Support\Facades\Event;
 
Event::listen(BatchCancelled::class, function (BatchCancelled $event) {
Log::warning("Batch {$event->batch->id} was cancelled.");
});

Pull Request: #58627

Eloquent Builders as Subqueries in Updates

Eloquent builders and relations can now be used directly as subqueries in update statements without converting to a base query:

// Before
FooModel::where('...')->update([
'bar_id' => BarModel::where('...')->toBase()->select('id'),
]);
 
// After
FooModel::where('...')->update([
'bar_id' => BarModel::where('...')->select('id'),
]);

The ->toBase() call is no longer required when passing an Eloquent builder as a subquery value.

Pull Request: #58692

withoutHeader() on Response

A new withoutHeader() method allows you to remove headers from HTTP responses, providing symmetry with the existing withoutCookie() method:

// Remove a single header
return response($content)->withoutHeader('X-Debug');
 
// Remove multiple headers
return response($content)->withoutHeader(['X-Debug', 'X-Powered-By', 'Server']);

Pull Request: #58671

Bug Fixes and Improvements

Testing:

  • assertJobs method on PendingBatchFake for batch job assertions (#58606)
  • Bus::assertBatched() with array support (#58659)
  • viewData() without key returns all view data on TestResponse (#58700)
  • Cache prefix isolation for parallel testing via TestCaches trait (#58691)

HTTP Client:

  • throwIfStatus/throwUnlessStatus now works for all status codes including 2xx and 3xx (#58724)

Database & Eloquent:

  • orderByPivotDesc() method for descending pivot column ordering (#58720)
  • whereBetween accepts DatePeriod and handles missing end dates (#58687)
  • SSL cert/key support for MySQL schema dump and load (#58690)
  • Fix Postgres sequence starting value for custom schemas/connections (#58199)
  • Adjust freshTimestamp for SQL Server (#58614)
  • Fix batch counts when deleteWhenMissingModels skips missing model jobs (#58541)

Strings & Helpers:

  • Stringable::deduplicate() accepts array of characters (#58649)
  • Fix Str::substrReplace for edge cases with negative offset or length (#58634)
  • Fix Str::isUrl() returning false for single-character domain names (#58686)
  • Replace substr with mb_substr for user agent encoding (#58703)

Queue & Middleware:

  • Allow specifying Redis connection on Redis-based queue middleware (#58656)
  • Fix Queue::fake() not releasing unique job locks between tests (#58718)

Translation & Localization:

  • Prevent duplicate locale checks in Lang::get() when locale matches fallback (#58626)
  • Fix trans_choice regex to allow negative ranges (#58648)

Framework & Internals:

  • Restore original dispatcher bindings after precognitive request — fixes Octane and Pest (#58716)
  • Handle binary data in Js::encode() debug renderer (#58618)
  • Add ArrayObject props to AsEncryptedArrayObject to match AsArrayObject (#58619)
  • Fix exception page pop-in for non-main frames (#58698)
  • Fix Laravel ASCII SVG character alignment (#58702, #58719)
  • Add deprecation to Request::get() (#58635)
  • Update reload tasks to include schedule:interruption (#58637)

References

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
Laravel Code Review

Get expert guidance in a few days with a Laravel code review

Visit Laravel Code Review
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $3200/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
Get expert guidance in a few days with a Laravel code review logo

Get expert guidance in a few days with a Laravel code review

Expert code review! Get clear, practical feedback from two Laravel devs with 10+ years of experience helping teams build better apps.

Get expert guidance in a few days with a Laravel code review
PhpStorm logo

PhpStorm

The go-to PHP IDE with extensive out-of-the-box support for Laravel and its ecosystem.

PhpStorm
Laravel Cloud logo

Laravel Cloud

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Cloud
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Harpoon: Next generation time tracking and invoicing logo

Harpoon: Next generation time tracking and invoicing

The next generation time-tracking and billing software that helps your agency plan and forecast a profitable future.

Harpoon: Next generation time tracking and invoicing
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit

The latest

View all →
Handling Large Datasets with Pagination and Cursors in Laravel MongoDB image

Handling Large Datasets with Pagination and Cursors in Laravel MongoDB

Read article
Driver-Based Architecture in Spatie's Laravel PDF v2 image

Driver-Based Architecture in Spatie's Laravel PDF v2

Read article
Why Your Livewire Dashboard Jumps (And How to Fix It) - Laravel In Practice EP18 image

Why Your Livewire Dashboard Jumps (And How to Fix It) - Laravel In Practice EP18

Read article
Laravel Live UK returns to London on June 18-19, 2026 image

Laravel Live UK returns to London on June 18-19, 2026

Read article
Laravel Related Content: Semantic Relationships Using pgvector image

Laravel Related Content: Semantic Relationships Using pgvector

Read article
Filament v5.2.0 Adds a Callout Component image

Filament v5.2.0 Adds a Callout Component

Read article