Optimizing Eloquent: Accessor Caching and Value Objects in Laravel

Optimizing Eloquent: Accessor Caching and Value Objects in Laravel

Laravel's Eloquent ORM is a powerful tool for working with databases, and it becomes even more potent when you leverage features like accessor caching and value objects. Let's dive into these concepts and see how they can enhance your Laravel applications.

Accessor Caching with shouldCache()

When dealing with computationally intensive accessors, caching can significantly improve performance. Laravel provides the shouldCache() method to easily cache the results of your accessors.

Here's how you can implement it:

class User extends Model
{
    protected function expensiveComputation(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => $this->heavyCalculation($value)
        )->shouldCache();
    }

    private function heavyCalculation($value)
    {
        // Simulate a time-consuming operation
        sleep(2);
        return "Processed: " . $value;
    }
}

In this example, expensiveComputation is an accessor that performs a heavy calculation. By calling shouldCache(), we ensure that the result is cached after the first access, avoiding redundant computations in subsequent calls.

Value Objects and Auto-Syncing

Laravel's Eloquent also seamlessly handles value objects, automatically syncing changes back to the model. This feature allows you to work with complex data structures more intuitively.

Here's an example:

class User extends Model
{
    protected function address(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => new Address($value),
            set: fn (Address $value) => $value->toArray()
        );
    }
}

class Address
{
    public function __construct(public string $street, public string $city) {}

    public function toArray()
    {
        return ['street' => $this->street, 'city' => $this->city];
    }
}

In this setup, you can work with the address attribute as an Address object:

$user = User::find(1);
$user->address->city = 'New York';
$user->save(); // The changes to the Address object are automatically synced

Disabling Object Caching

While object caching is generally beneficial, there might be scenarios where you want to disable it. Laravel provides the withoutObjectCaching() method for such cases:

class User extends Model
{
    protected function dynamicData(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => new DynamicData($value)
        )->withoutObjectCaching();
    }
}

This is particularly useful for attributes that need to be re-evaluated every time they're accessed, even within the same request cycle.

By leveraging these Eloquent features, you can create more efficient, expressive, and maintainable Laravel applications. Whether you're dealing with complex computations, structured data, or dynamic attributes, Laravel provides the tools to handle these scenarios elegantly.

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe