Advanced Attribute Casting in Laravel 12: A Complete Developer’s Guide

Laravel PHP
October 15th, 2025

Leveraging Attribute Casting for Advanced Data Transformations in Laravel 12

When working with Eloquent models in Laravel, most developers use attribute casting in a simple way, i.e., booleans, dates, or arrays. But Laravel 12 introduces even more power and flexibility, allowing you to transform model attributes cleanly, elegantly, and securely.

In this in-depth guide, we’ll go beyond the basics to explore:

  • Why attribute casting matters
  • How custom casts work under the hood
  • Real-world casting examples (currency, encryption, geolocation & more)
  • How to test and optimize your casts
  • Pro tips to avoid common mistakes

Whether you’re a Laravel beginner looking to level up or an advanced developer cleaning up your model logic, this guide will help you build more expressive and maintainable code.


What Is Attribute Casting?

Attribute casting in Laravel allows you to automatically convert database values to a specific type when they are accessed, and back again when they’re stored.

Example of basic casting:

<?php

class User extends Model
{
    protected $casts = [
        'is_active' => 'boolean',
        'email_verified_at' => 'datetime',
        'meta' => 'array',
    ];
}

Now, whenever you access $user->is_active, you’ll get a boolean true or false instead of a 1 or 0. Similarly, email_verified_at is automatically converted into a Carbon datetime instance.

This keeps your model logic clean and saves you from writing manual conversions everywhere.


How Casting Works Internally in Laravel 12?

Under the hood, Laravel looks at the $casts property on your model and determines how to transform data between the database and your application.

  • When retrieving data, Laravel runs the get method of the cast (or built-in cast type).
  • When saving data, it runs the set method.
  • You can use:
    • Built-in cast types (boolean, datetime, array, etc.)
    • Custom cast classes by implementing the CastsAttributes interface
    • Value object casting (casting directly to a class)

This means you can completely control how your model values behave, making your code more reusable and testable.


Creating a Simple Custom Cast

Let’s start with something simple.

Say we want to automatically uppercase a name field when retrieved, and lowercase it before storing.

<?php

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class UppercaseCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return strtoupper($value);
    }

    public function set($model, $key, $value, $attributes)
    {
        return strtolower($value);
    }
}

Register it in your Model:

class User extends Model
{
    protected $casts = [
        'name' => UppercaseCast::class,
    ];
}

Now, if you save John Doe, it'll be stored as john doe in the database, but retrieved as JOHN DOE.


Example 1: Casting Currency Values

Let’s say you store prices in cents to avoid floating point precision issues, but want to display them in dollars when accessing them.

<?php

class MoneyCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return number_format($value / 100, 2);
    }

    public function set($model, $key, $value, $attributes)
    {
        return (int) ($value * 100);
    }
}

Usage in your Model:

<?php

class Product extends Model
{
    protected $casts = [
        'price' => MoneyCast::class,
    ];
}

Now:

$product->price = 29.99;
$product->save();

// Database: 2999
// Accessed value: "29.99"

Why this matters: You keep consistent, safe values in your database and avoid formatting logic scattered throughout your views.


Example 2: Encrypted Fields with Automatic Decryption

Sometimes you want to keep sensitive fields encrypted at rest — e.g., tokens, API keys, or personal data.

Laravel makes this simple with a custom cast.

<?php

use Illuminate\Support\Facades\Crypt;

class EncryptedCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return $value ? Crypt::decryptString($value) : null;
    }

    public function set($model, $key, $value, $attributes)
    {
        return $value ? Crypt::encryptString($value) : null;
    }
}

Register it:

<?php

class User extends Model
{
    protected $casts = [
        'ssn' => EncryptedCast::class,
    ];
}

Whenever you access $user->ssn, Laravel automatically decrypts it for you. When you save, it’s encrypted automatically.

No more remembering to call Crypt::encryptString() manually.


Example 3: Geolocation Casting (Latitude/Longitude)

Suppose you store geolocation as a simple string like "40.7128,-74.0060".

You can make it more developer-friendly with a GeoCast.

<?php

class GeoCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        [$lat, $lng] = explode(',', $value);
        return (object) [
            'lat' => (float) $lat,
            'lng' => (float) $lng,
        ];
    }

    public function set($model, $key, $value, $attributes)
    {
        return "{$value->lat},{$value->lng}";
    }
}

Model:

<?php

class User extends Model
{
    protected $casts = [
        'location' => GeoCast::class,
    ];
}

Usage:

$user->location = (object) ['lat' => 37.7749, 'lng' => -122.4194];
$user->save();

echo $user->location->lat; // 37.7749

This makes geolocation easy to work with and keeps the database schema simple.


Pro Tip: Casting to Value Objects

Laravel 12 allows casting directly to a class (e.g., a value object) if it implements the right interface.

<?php

class Money
{
    public function __construct(public int $amountInCents) {}

    public function asDollars(): string
    {
        return number_format($this->amountInCents / 100, 2);
    }
}

Model:

<?php

protected $casts = [
    'price' => Money::class,
];

Usage:

echo $product->price->asDollars(); // "29.99"

This aligns perfectly with domain-driven design and keeps business logic separate from models.


Testing Custom Casts

You can test custom cast classes independently of your model.

it('casts money correctly', function () {
    $cast = new MoneyCast();

    $this->assertEquals('29.99', $cast->get(null, 'price', 2999, []));
    $this->assertEquals(2999, $cast->set(null, 'price', 29.99, []));
});
  • This ensures your casts behave predictably
  • Makes refactoring safer
  • Reduces bugs in your application

Performance & Caching Tips

  • Use casts wisely: complex transformations should be cached.
  • Avoid expensive operations (e.g., external API calls) in casts unless cached.
  • Prefer value objects for heavy business logic.
  • Laravel 12 optimizes cast hydration, so using them efficiently can improve both clarity and performance.

When Not to Use Casts

Although casts are powerful, they’re not always the right tool:

  • If the transformation involves multiple model attributes → consider accessors or services.
  • If it requires external data every time → cache or process elsewhere.
  • If it’s view-specific formatting (e.g., currency symbols) → handle in Blade or presenters.

Conclusion

Attribute casting in Laravel 12 is more than just a convenient shortcut for dates and booleans. It’s a powerful pattern for clean, reusable, and secure data transformations.

With custom casts, you can:

  • Centralize logic like currency, encryption, geolocation
  • Keep your models lightweight and expressive
  • Boost testability and consistency across your app
  • Embrace domain-driven patterns

Tip: Writing reusable casts and sharing them across your models can significantly reduce duplicated code, make your app more robust, and bring your data layer closer to your domain logic.

Process Followed

1. Discover

In this process, I learn more about the requirements from you and/or from the client, and come up with varios permutations and combinations to meet the requirements.

2. Design

Once I learn properly, I do the design of the requirements that you gave keeping things aesthetically pleasing & useable for your audience.

3. Develop

Once you and/or the client is happy with the design(s), I start with the development process of the said requirements.

4. Deploy

After development, I will send the developed task to the client for reviewing. Once confirmed, will be deployed to the live server.

Tech Stack

HTML 5

HTML 5

CSS 3

CSS 3

TailwindCSS

TailwindCSS

JavaScript

JavaScript

PHP

PHP

MySQL

MySQL

Laravel

Laravel

VueJs

VueJs

Spare time Projects

Few of the simple projects simply to learn.

View Projects →
Copyright © 2025, BMehul. All Rights Reserved.
Built with A heart icon using Laravel v12.33.0