시작하기
액세서, 뮤테이터, 속성 캐스트는 Eloquent 모델의 속성값을 모델 인스턴스에서 취득·설정할 때 변환하는 구조입니다.
- 액세서 — DB에서 취득한 원시 값을 가공해 애플리케이션에 전달
- 뮤테이터 — 애플리케이션에서 세팅된 값을 가공해 DB에 저장
- 캐스트 — 추가 메서드 없이 속성의 타입 변환을 선언적으로 정의
액세서 정의
액세서를 정의하려면 모델에 protected 메서드를 추가합니다. 메서드 이름은 카멜케이스, 반환값 타입은 Illuminate\Database\Eloquent\Casts\Attribute로 합니다.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 사용자의 퍼스트 네임을 취득합니다.
*/
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
);
}
}
get 클로저에 DB의 원시 값이 전달됩니다. 모델 인스턴스에서 first_name 프로퍼티로 접근할 수 있습니다.
$user = User::find(1);
$firstName = $user->first_name; // ucfirst() 가 적용된 값
액세서로 계산한 값을 JSON/배열에 포함시키고 싶은 경우, 모델의 $appends 프로퍼티에 스네이크 케이스로 추가해 주십시오.
여러 속성으로부터 값 객체를 생성
get 클로저는 두 번째 인수로 $attributes(모델의 모든 속성)를 받을 수 있습니다. 여러 컬럼을 조합해 하나의 값 객체를 반환할 수 있습니다.
use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
);
}
액세서 캐시
값 객체를 반환하는 액세서는 Eloquent가 같은 인스턴스를 반환하도록 자동으로 캐시합니다. 문자열이나 숫자 등 기본 타입에서도 캐시하고 싶은 경우 shouldCache()를 호출합니다.
protected function hash(): Attribute
{
return Attribute::make(
get: fn (string $value) => bcrypt(gzuncompress($value)),
)->shouldCache();
}
객체의 캐시를 무효로 하고 싶은 경우 withoutObjectCaching()을 사용합니다.
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
)->withoutObjectCaching();
}
뮤테이터 정의
뮤테이터는 Attribute::make()의 set 인수로 정의합니다. 액세서와 같은 메서드에 함께 정리할 수 있습니다.
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
모델에 값을 세팅하면 set 클로저가 호출됩니다.
$user = User::find(1);
$user->first_name = 'SALLY'; // strtolower() 가 적용되어 'sally' 가 저장됨
여러 속성에 쓰기
set 클로저에서 배열을 반환하면, 여러 컬럼을 함께 업데이트할 수 있습니다.
use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
set: fn (Address $value) => [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
],
);
}
속성 캐스트
캐스트는 액세서·뮤테이터를 쓰지 않아도 속성의 타입 변환을 선언할 수 있는 간편한 방법입니다. 모델의 casts() 메서드에서 배열을 반환합니다.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected function casts(): array
{
return [
'is_admin' => 'boolean',
'score' => 'float',
'settings' => 'array',
'created_at' => 'datetime',
];
}
}
내장 캐스트 목록
| 캐스트 | 설명 |
|---|
integer / int | 정수 |
float / double / real | 부동소수점 수 |
decimal:<자릿수> | 지정 자릿수의 소수 |
string | 문자열 |
boolean / bool | 진위값(0/1 포함) |
array | JSON을 배열로 상호 변환 |
object | JSON을 객체로 상호 변환 |
collection | JSON을 컬렉션으로 변환 |
date | 날짜(Carbon) |
datetime | 일시(Carbon) |
immutable_date | 불변 날짜 |
immutable_datetime | 불변 일시 |
timestamp | UNIX 타임스탬프 |
hashed | 저장 시에 해시화 |
encrypted | 저장 시에 암호화 |
null 속성은 캐스트되지 않습니다. 또한 릴레이션 이름과 같은 이름의 캐스트나, 주 키에의 캐스트는 정의하지 마십시오.
Stringable 캐스트
AsStringable을 사용하면 속성을 Illuminate\Support\Stringable 객체로 다룰 수 있습니다.
use Illuminate\Database\Eloquent\Casts\AsStringable;
protected function casts(): array
{
return [
'bio' => AsStringable::class,
];
}
배열·JSON 캐스트
JSON/TEXT 컬럼을 PHP 배열로 투과적으로 다룰 수 있습니다.
protected function casts(): array
{
return [
'options' => 'array',
];
}
$user = User::find(1);
// 자동으로 PHP 배열로 취득
$options = $user->options;
// 변경해서 저장하면 자동으로 JSON 직렬화됨
$user->options = array_merge($options, ['theme' => 'dark']);
$user->save();
-> 연산자로 JSON의 특정 키만 업데이트할 수도 있습니다.
$user->update(['options->theme' => 'dark']);
AsArrayObject / AsCollection 캐스트
표준 array 캐스트는 배열의 특정 오프셋을 직접 변경하려고 하면 오류가 발생합니다. AsArrayObject나 AsCollection을 사용하면 이 문제를 회피할 수 있습니다.
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Casts\AsCollection;
protected function casts(): array
{
return [
'options' => AsArrayObject::class, // ArrayObject 로 다룸
'tags' => AsCollection::class, // Collection 으로 다룸
];
}
커스텀 컬렉션 클래스를 사용하고 싶은 경우 using()을 지정합니다.
use App\Collections\TagCollection;
use Illuminate\Database\Eloquent\Casts\AsCollection;
protected function casts(): array
{
return [
'tags' => AsCollection::using(TagCollection::class),
];
}
일시 캐스트
created_at / updated_at은 기본적으로 Carbon으로 캐스트됩니다. 추가의 일시 컬럼도 동일하게 정의할 수 있습니다.
protected function casts(): array
{
return [
'published_at' => 'datetime',
'expires_at' => 'immutable_datetime',
];
}
포맷을 지정하면 JSON 직렬화 시에 그 포맷이 사용됩니다.
protected function casts(): array
{
return [
'published_at' => 'datetime:Y-m-d',
];
}
모든 날짜의 기본 직렬화 포맷을 바꾸고 싶은 경우 serializeDate()를 오버라이드합니다(DB 저장 포맷에는 영향을 주지 않습니다).
use DateTimeInterface;
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d');
}
immutable_datetime을 사용하면 Carbon 대신 CarbonImmutable이 반환됩니다. 원래 인스턴스를 변경하지 않고 일시 조작을 할 수 있어 부작용이 없는 코드를 쓰기 쉬워집니다.
Enum 캐스트
PHP 8.1 이후의 Backed Enum을 캐스트로 지정할 수 있습니다.
<?php
namespace App\Enums;
enum ServerStatus: string
{
case Provisioned = 'provisioned';
case Ready = 'ready';
case Archived = 'archived';
}
use App\Enums\ServerStatus;
protected function casts(): array
{
return [
'status' => ServerStatus::class,
];
}
DB에는 Enum의 백킹 값(string 또는 int)이 저장되고, 취득 시에는 Enum 인스턴스로 변환됩니다.
$server = Server::find(1);
if ($server->status === ServerStatus::Provisioned) {
$server->status = ServerStatus::Ready;
$server->save();
}
Enum 의 배열 캐스트
여러 Enum 값을 1개의 컬럼에 배열로 저장하고 싶은 경우 AsEnumCollection을 사용합니다.
use App\Enums\ServerStatus;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
protected function casts(): array
{
return [
'statuses' => AsEnumCollection::of(ServerStatus::class),
];
}
쿼리 시의 캐스트
쿼리 실행 시에 동적으로 캐스트를 적용하려면 withCasts()를 사용합니다.
use App\Models\Post;
use App\Models\User;
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id'),
])->withCasts([
'last_posted_at' => 'datetime',
])->get();
커스텀 캐스트
독자적인 캐스트 클래스를 작성할 수도 있습니다. CastsAttributes 인터페이스를 구현하고 get과 set 메서드를 정의합니다.
php artisan make:cast AsJson
상세한 구현 방법(Value Object 패턴, 인바운드 캐스트, Castables 등)은 다음의 상급 페이지를 참조하십시오.
커스텀 캐스트 상세 설명
CastsAttributes 인터페이스의 구현 방법이나, Value Object 패턴·Castables 등 상급의 커스텀 캐스트를 설명합니다.
관련 페이지
Eloquent API 리소스
모델을 일관된 JSON API 응답으로 변환하는 리소스 클래스의 사용법을 확인합니다.