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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Custom casts keep serialization logic in one place instead of scattering json_decode across your models.
- 2Casting to an immutable value object gives model attributes real types and behavior rather than raw arrays.
- 3Validating the incoming type on set catches misuse at the boundary before bad data reaches the database.
Related explainers
php
<?php namespace App\Validation;
Building a reusable address form validator in PHP
validation
error-accumulation
regex
Intermediate
9 steps
php
<?php namespace App\Http\Controllers;
A cached autocomplete endpoint in Laravel
caching
validation
query-ranking
Intermediate
8 steps
typescript
interface UserAgentInfo { browser: { name: string; version: string }; os: { name: string; version: string }; device: 'mobile' | 'tablet' | 'desktop';
Parsing a user-agent string with ordered rules
regex
parsing
pattern-matching
Intermediate
9 steps
rust
use axum::{ extract::Query, response::IntoResponse, Json,
Parsing query strings in Axum handlers
deserialization
query-parameters
defaults
Intermediate
7 steps
php
<?php declare(strict_types=1);
Normalizing human names in PHP
unicode
text-normalization
transliteration
Intermediate
8 steps
php
<?php namespace App\Http\Controllers;
Handling Stripe webhooks in Laravel
webhooks
signature-verification
dependency-injection
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-a-custom-eloquent-cast-wraps-an-address-in-laravel-explained-php-deba/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.