Laravel 11: Building a Custom Data Formatting System with Attribute Casting

Samuel
3 min readJun 18, 2024

--

Welcome back, Laravel enthusiasts, to the inaugural post in our series “Mastering Laravel’s Elements & Features with Hands-On Projects”! Throughout this series, we’ll be exploring the essential building blocks of Laravel, focusing on practical projects that leverage the latest and greatest features of Laravel 11.

Today, we’re diving into the world of data transformation with Attribute Casting. This powerful feature, refined in Laravel 11, provides an elegant way to manage how data is exchanged between your PHP application and your database, ensuring consistency and simplifying your code.

Why Attribute Casting Matters: A Practical Example

Imagine you’re building a cutting-edge e-commerce platform using Laravel 11. You need to store product prices, which are inherently numbers. But when a user browses your site, you want to display those prices in a polished format, like “$10.00” instead of a plain “10”. Manually formatting this every time would be tedious and error-prone.

This is where Attribute Casting shines. It acts as an invisible translator, automatically converting data types during database retrieval and storage. No more cluttered code with repetitive formatting logic!

Laravel 11 vs. Laravel 10: A Casting Evolution

Laravel 11 introduces a more streamlined and expressive way to define custom casts using the `Illuminate\Database\Eloquent\Casts\Attribute` class. Let’s contrast this with the Laravel 10 approach:

Laravel 10:

use App\Casts\PriceCast;

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

// ... Separate PriceCast class implementation

Laravel 11:

use Illuminate\Database\Eloquent\Casts\Attribute;

class Product extends Model
{
protected function price(): Attribute
{
return Attribute::make(
get: fn (int $value) => '$' . number_format($value / 100, 2),
set: fn (string $value) => (int) str_replace(['$', ','], '', $value) * 100,
);
}
}

Key Differences:

- No More `$casts` Property: In Laravel 11, we define the casting logic directly within a dedicated method for the attribute (e.g., `price()`).
- The Power of `Attribute`: The `Attribute` class provides a fluent and readable way to define how the attribute is accessed (`get`) and mutated (`set`) using closures.
- Simplified for Clarity: For simpler casts, you no longer need to create separate cast classes. The logic can be neatly contained within your model.

Building Our Custom Price Formatter

Let’s put this into practice. We’ll create a custom price formatting system for our e-commerce platform directly within our `Product` model:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;

class Product extends Model
{
// ... other model properties

protected function price(): Attribute
{
return Attribute::make(
get: fn (int $value) => '$' . number_format($value / 100, 2),
set: fn (string $value) => (int) str_replace(['$', ','], '', $value) * 100,
);
}
}

Explanation:

- `price()` Method: This method returns an `Attribute` instance.
- `get` Closure: When retrieving the `price`, this closure formats the raw database value (an integer representing cents) into a user-friendly string with a dollar sign and two decimal places.
- `set` Closure: When saving the `price`, this closure converts the user-input string (e.g., “$15.99”) back into an integer representing cents, stripping out currency symbols and commas.

Effortless Data Handling

With our custom cast in place, using product prices becomes incredibly easy:

// Create a new product
$product = Product::create(['name' => 'Designer Hoodie', 'price' => '29.99']);

// Retrieve and display the formatted price
echo $product->price; // Output: $29.99

Laravel 11 handles everything behind the scenes, making our code cleaner, more maintainable, and a joy to work with.

Stay Tuned for More!

Attribute Casting is just the tip of the iceberg when it comes to Laravel 11’s powerful features. Join us for the next installment in our series, where we’ll explore another exciting element and build a practical project together.

Official documentation here.

Happy coding!

--

--

Samuel

Versatile Full-Stack Developer | PHP, Python3, WordPress | Author & GuardGeo Owner | Passionate about secure, efficient coding and continuous growth.