← Back to all snippets
PHP

Custom Attribute Casting with Value Objects

Implement custom attribute casting in Eloquent to transform database values into rich PHP value objects, enhancing domain logic and type safety.

// In app/Casts/MoneyCast.php
namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use InvalidArgumentException;

class Money
{
    public function __construct(public float $amount, public string $currency = 'USD') {}

    public function format(): string
    {
        return sprintf('%s %.2f', $this->currency, $this->amount);
    }

    public function __toString(): string
    {
        return (string) $this->amount;
    }
}

class MoneyCast implements CastsAttributes
{
    public function get(Model $model, string $key, mixed $value, array $attributes): mixed
    {
        return new Money((float) $value);
    }

    public function set(Model $model, string $key, mixed $value, array $attributes): mixed
    {
        if (!$value instanceof Money) {
            throw new InvalidArgumentException('The given value is not a Money instance.');
        }
        return $value->amount;
    }
}

// In app/Models/Product.php
namespace App\Models;

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

class Product extends Model
{
    use HasFactory;

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

// Usage:
// $product = Product::find(1);
// echo $product->price->format(); // e.g., "USD 12.00"
// $product->price = new Money(15.99);
// $product->save();
How it works: Custom attribute casting allows you to define a class that handles how a model attribute is stored in the database and retrieved as a PHP type. This example demonstrates casting a `price` attribute into a `Money` value object. The `MoneyCast` class implements `CastsAttributes`, providing `get` and `set` methods to convert between the database value (float) and the `Money` object. This pattern enhances type safety, encapsulates business logic within value objects, and keeps your model cleaner.

Need help integrating this into your project?

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

Hire DigitalCodeLabs