PHP

Implementing Custom Attribute Casting in Laravel Eloquent

Create custom attribute casts in Laravel Eloquent to handle complex data types like value objects or encrypted strings, ensuring robust and flexible data management.

<?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

// Example Value Object
class Money
{
    public function __construct(public int $amount, public string $currency = 'USD') {}

    public function __toString(): string
    {
        return $this->currency . ' ' . number_format($this->amount / 100, 2);
    }

    public function toArray(): array
    {
        return ['amount' => $this->amount, 'currency' => $this->currency];
    }
}

class MoneyCast implements CastsAttributes
{
    /**
     * Cast the given value.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  mixed  $value
     * @param  array  $attributes
     * @return \App\Casts\Money|null
     */
    public function get($model, string $key, $value, array $attributes): ?Money
    {
        if (is_null($value)) {
            return null;
        }
        $data = json_decode($value, true);
        return new Money($data['amount'], $data['currency'] ?? 'USD');
    }

    /**
     * Prepare the given value for storage.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  \App\Casts\Money|null  $value
     * @param  array  $attributes
     * @return string|null
     */
    public function set($model, string $key, $value, array $attributes): ?string
    {
        if (is_null($value)) {
            return null;
        }
        return json_encode($value->toArray());
    }
}

// In your Product model
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Casts\MoneyCast;

class Product extends Model
{
    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'price' => MoneyCast::class,
    ];
}

// Usage:
// $product = Product::find(1);
// echo $product->price; // Accesses the Money object
// $product->price = new \App\Casts\Money(12999, 'EUR');
// $product->save();
How it works: Custom casts provide a powerful way to handle complex attribute types by mapping database values to PHP objects and vice-versa. This snippet defines a Money value object and a MoneyCast class to serialize/deserialize it to/from JSON in the database. By listing MoneyCast in the $casts array of the Product model, the price attribute will automatically be cast to and from a Money object, simplifying value object integration.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs