The Laravel team released v13.42.0 with uuid() and ulid() methods for request input, a MigrationFailed event, a reason on skipped scheduled tasks, a closure hook for detecting lost database connections, and more:
uuid()andulid()on requests and otherInteractsWithDataclasses- A
MigrationFailedevent - Skip reasons on the
ScheduledTaskSkippedevent schedule:list --jsonreports each task's own timezoneLostConnectionDetector::detectUsing()Uri::origin()- Macros on
PendingProcess - Support for the
ably/pubsub-serverpackage
UUID and ULID Request Input
Pawel added uuid() and ulid() next to the existing date() and enum() helpers. They return a typed object instead of a string:
$request->uuid('order_id'); // Ramsey\Uuid\UuidInterface|null $request->ulid('order_id'); // Symfony\Component\Uid\Ulid|null $request->safe()->uuid('order_id');
Missing or empty input returns null. Invalid input throws an exception. The methods come from the InteractsWithData trait, so they also work on Fluent, validated input, Uri query strings, component attributes, and command input.
The ulid() method only accepts a real ULID string. A UUID passed to it throws instead of being converted to a different ULID.
See #62327 and #62348 for more details.
MigrationFailed Event
Jack Bayliss added a MigrationFailed event that fires when a migration throws. The event has the same migration, method, and name properties as the other migration events, plus the exception. The exception is still thrown after the event fires.
On MySQL, schema changes such as ALTER TABLE are not rolled back when a later statement in the migration fails. You can use the event to alert your team or take the app down before users hit the half-applied schema:
use Illuminate\Database\Events\MigrationFailed; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Log; Event::listen(function (MigrationFailed $event) { Artisan::call('down'); Log::channel('slack')->critical("Migration [{$event->name}] failed", [ 'exception' => $event->exception->getMessage(), ]); });
See #62342 for more details.
Scheduler Skip Reasons and JSON Timezones
Jack Bayliss also added a reason property to the ScheduledTaskSkipped event. It holds a ScheduledTaskSkipReason enum with three cases: ConditionNotMet, Paused, and RanOnAnotherServer.
Event::listen(function (ScheduledTaskSkipped $event) { Log::info('Scheduled task skipped', [ 'task' => $event->task->getSummaryForDisplay(), 'reason' => $event->reason?->value, ]); });
Francisco Madeira changed schedule:list --json to return each task's own cron expression and timezone. Before, every expression was converted to the app timezone, so stored output was off by an hour after a DST change. Passing --timezone still converts every task to that timezone. If you parse this JSON, check tasks that set their own timezone(), because their expression, timezone, and next_due_date values change.
See #62294 and #62352 for more details.
Custom Lost Connection Detection
Laravel reconnects to the database when an exception matches a list of known lost connection messages. The new LostConnectionDetector::detectUsing() method, also from Jack Bayliss, adds your own check without binding a custom detector:
use Illuminate\Database\LostConnectionDetector; LostConnectionDetector::detectUsing(function (Throwable $e) { return str_contains($e->getMessage(), 'vttablet: rpc error'); });
When the callback returns false, Laravel checks the built-in messages.
See #62316 for more details.
Uri::origin()
Naoya Miyagawa added origin() to the Uri class. It returns the scheme, host, and port, and normalizes them, so https://App.example.com:443 becomes https://app.example.com:
use Illuminate\Support\Uri; $sameOrigin = Uri::of($first)->origin() === Uri::of($second)->origin();
The framework now requires league/uri 7.6 or later.
See #62326 for more details.
PendingProcess Macros
Richard van Baarsen made PendingProcess macroable. Before, a macro on the Process factory only worked as the first call in a chain:
use Illuminate\Process\PendingProcess; use Illuminate\Support\Facades\Process; PendingProcess::macro('withHerd', function () { return $this->env(['PATH' => $herdBin.':'.getenv('PATH')]); }); Process::tty()->withHerd()->run('composer global install');
See #62351 for more details.
Ably Package Rename
The Ably PHP SDK was renamed from ably/ably-php to ably/pubsub-server. Mior Muhammad Zaki added support for version 2 of the new package, and php artisan install:broadcasting --ably now installs ably/pubsub-server. Apps on ably/ably-php 1.x keep working.
See #62315 and #62322 for more details.
Other Fixes
cursor()now respectsModel::preventLazyLoading()(#62345)TokenGuard::validate()hashes the token when the guard has hashing enabled. Before, it returnedfalsefor valid tokens (#62336)- A commit that fails from a lost connection now discards the PDO, so PostgreSQL connections reconnect instead of failing every later transaction (#62366)
foreignIdFor()creates abigintcolumn for models with$keyType = 'integer'instead of achar(36)column (#62365)- JSON:API compound documents include identical
BelongsToManyresources once (#62360) dispatch()->afterResponse()reports exceptions instead of trying to render them (#62313)