php 46 lines · 7 steps

How a custom Eloquent cast wraps an Address in Laravel

A Laravel custom cast translates a JSON database column into an Address value object and back.

Explained by highlit
1<?php
2 
3namespace App\Casts;
4 
5use App\ValueObjects\Address;
6use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
7use Illuminate\Database\Eloquent\Model;
8 
9class AddressCast implements CastsAttributes
10{
11 public function get(Model $model, string $key, mixed $value, array $attributes): ?Address
12 {
13 if ($value === null) {
14 return null;
15 }
16 
17 $data = json_decode($value, true, 512, JSON_THROW_ON_ERROR);
18 
19 return new Address(
20 street: $data['street'],
21 city: $data['city'],
22 postalCode: $data['postal_code'],
23 country: $data['country'],
24 );
25 }
26 
27 public function set(Model $model, string $key, mixed $value, array $attributes): array
28 {
29 if ($value === null) {
30 return [$key => null];
31 }
32 
33 if (! $value instanceof Address) {
34 throw new \InvalidArgumentException('The given value is not an Address instance.');
35 }
36 
37 return [
38 $key => json_encode([
39 'street' => $value->street,
40 'city' => $value->city,
41 'postal_code' => $value->postalCode,
42 'country' => $value->country,
43 ], JSON_THROW_ON_ERROR),
44 ];
45 }
46}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Custom casts keep serialization logic in one place instead of scattering json_decode across your models.
  2. 2Casting to an immutable value object gives model attributes real types and behavior rather than raw arrays.
  3. 3Validating the incoming type on set catches misuse at the boundary before bad data reaches the database.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a custom Eloquent cast wraps an Address in Laravel — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code