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.