News

Tagged Memoized Cache and Model Refreshes in Laravel 13.33

Published
Tagged Memoized Cache and Model Refreshes in Laravel 13.33 image

The Laravel team released v13.33.0 with tag support for the memoized cache, a Refreshes model attribute that reloads generated columns after a write, and more:

Tagged Memoized Cache

Joost de Bruijn contributed a tags() method to the memoized cache store, so Cache::memo() now works with tagged caches. Reads inside the same request hit the cache backend once and come from memory after that:

// Two calls, one round trip to Redis
Cache::memo()->tags(['permissions'])->get("permissions:{$user->id}");
Cache::memo()->tags(['permissions'])->get("permissions:{$user->id}");
 
// Writes go to the tagged cache and drop the memoized copy
Cache::memo()->tags(['permissions'])->put("permissions:{$user->id}", $permissions);
 
// Flushing the tag also clears the memoized entries
Cache::memo()->tags(['permissions'])->flush();

Before this release, the same pattern meant wrapping a tagged cache call in a second Cache::store('array') lookup by hand. Laravel News covered the untagged version when it shipped in Laravel 12.9.

Read more in Memoize Tagged Cache Reads in Laravel. See #61593 for more details.

Refresh Model Attributes After Writes

Caleb White contributed a #[Refreshes] attribute (and a matching $refreshes property) that reloads specific columns from the database after a model is created or updated. It is meant for virtualAs and storedAs columns and other values the database sets, which are otherwise missing or stale on the in-memory model until you call refresh():

use Illuminate\Database\Eloquent\Attributes\Refreshes;
 
#[Refreshes('name')]
class User extends Model
{
//
}
 
$user = User::create(['first_name' => 'Taylor', 'last_name' => 'Otwell']);
 
$user->name; // "Taylor Otwell" without calling refresh()

The refresh runs one query for the listed columns only, on the write connection. The attribute accepts an array or variadic column names, and the $refreshes property works the same way if you do not use attributes. Read more in Refresh Generated Columns After Saving an Eloquent Model.

See #61523 for more details.

Store a Real NULL With AsCollection and AsArrayObject

Zein Ahmad contributed an opt-in nullable() mode for the AsCollection and AsArrayObject casts. Assigning null to one of these casts stores the JSON string "null" in the column, so whereNull() never matches the row. With nullable(), the cast stores a database NULL instead:

protected function casts(): array
{
return [
'items' => AsCollection::class, // unchanged: stores "null"
'meta' => AsCollection::nullable(), // stores NULL
'options' => AsArrayObject::nullable(),
];
}

Read more in Store NULL Instead of "null" With AsCollection::nullable(). See #61596 for more details.

inplace() and lock() for Index Migrations

Sander Muller contributed an inplace() modifier for index and foreign key operations, along with a lock() modifier, so a MySQL migration can request ALGORITHM=INPLACE and LOCK=NONE instead of falling back to a blocking table rebuild:

Schema::table('video_sessions', function (Blueprint $table) {
$table->index('foo', 'foo_index')->inplace()->lock('none');
});

The modifier works on the following methods:

  • index()
  • unique()
  • primary()
  • fullText()
  • spatialIndex()
  • foreign()

It mirrors the instant() modifier that column definitions already have.

See #61602 for more details.

Form Request Attributes From Parent Classes

Md Sukkur Ali fixed form request attributes so a child request picks them up from its parent class. PHP does not inherit attributes, so attributes such as #[StopOnFirstFailure] on a shared base request were ignored by every subclass:

#[StopOnFirstFailure]
#[FailOnUnknownFields]
abstract class ApiRequest extends FormRequest
{
//
}
 
// Both attributes now apply
class StorePostRequest extends ApiRequest
{
//
}

See #61586 for more details.

Opt Out of Killing the Worker on Timeout

Jack Bayliss contributed a Worker::$killOnTimeout flag. By default, a job that exceeds its timeout kills the whole worker process, and the supervisor boots a fresh one. Set the flag to false and the worker throws a TimeoutExceededException instead, so the job can clean up and the worker keeps running:

use Illuminate\Queue\Worker;
 
Worker::$killOnTimeout = false;

Warning: a job that wraps its handle() body in a broad try/catch can swallow the exception.

A related PR by Kieran Brown adds Worker::killUsing(), a hook that runs before the SIGKILL so a custom exit code can reach the supervisor (#61622).

See #61591 for more details.

mockArtisan() and realArtisan() Test Helpers

Jenthe Noordsij contributed two test helpers that split the two jobs of $this->artisan(). The mockArtisan() method always returns a PendingCommand for expectations, and realArtisan() always runs the command and returns the exit code as an int, so you no longer toggle $mockConsoleOutput to switch between the two:

$this->mockArtisan('inspire')
->expectsOutputToContain('Simplicity')
->assertExitCode(0);
 
$code = $this->realArtisan('migrate', ['--force' => true]);

See #61588 for more details.

Release Notes

You can see the complete list of new features and updates below and the diff between 13.32.0 and 13.33.0 on GitHub. The following release notes are directly from the changelog:

v13.33.0

Paul Redmond photo

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

Sponsored

laravelcloud logo
Laravel Cloud

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

Visit Laravel Cloud

The latest

View all →
Laravel Live Denmark 2026 Talks Are Now on YouTube image

Laravel Live Denmark 2026 Talks Are Now on YouTube

Read article
Live Stream: Building a Social Network in PHP in 48 Hours image

Live Stream: Building a Social Network in PHP in 48 Hours

Read article
Health for Laravel: Kubernetes Probes and Prometheus Metrics image

Health for Laravel: Kubernetes Probes and Prometheus Metrics

Read article
Fast Excel 5.x Adds Streaming Imports and Safer Exports image

Fast Excel 5.x Adds Streaming Imports and Safer Exports

Read article
What We Know About Laravel 14 image

What We Know About Laravel 14

Read article
Difflock: Lint Laravel Migrations and Diff Your Schema image

Difflock: Lint Laravel Migrations and Diff Your Schema

Read article