Eloquent 직렬화
번역일: 2026년 6월 20일
Eloquent 직렬화
소개
Laravel로 API를 개발할 때, Eloquent 모델과 연관 관계 데이터를 배열이나 JSON 형태로 변환해야 하는 경우가 자주 있습니다. Eloquent는 이러한 변환을 간편하게 처리할 수 있는 메서드를 제공하며, 직렬화 결과에 포함할 속성도 세밀하게 제어할 수 있습니다.
NOTE
Eloquent 모델과 컬렉션의 JSON 직렬화를 더욱 유연하게 다루고 싶다면 Eloquent API 리소스 문서를 참고하세요.
모델과 컬렉션 직렬화
배열로 직렬화
모델과 로드된 연관 관계를 배열로 변환하려면 toArray 메서드를 사용합니다. 이 메서드는 재귀적으로 동작하므로, 모든 속성과 연관 관계(연관 관계의 연관 관계까지)가 배열로 변환됩니다.
use App\Models\User;
$user = User::with('roles')->first();
return $user->toArray();연관 관계는 제외하고 모델의 속성만 배열로 변환하려면 attributesToArray 메서드를 사용하세요.
$user = User::first();
return $user->attributesToArray();컬렉션 인스턴스에서 toArray를 호출하면 컬렉션 전체를 배열로 변환할 수 있습니다.
$users = User::all();
return $users->toArray();JSON으로 직렬화
모델을 JSON으로 변환하려면 toJson 메서드를 사용합니다. toArray와 마찬가지로 재귀적으로 동작하며, 모든 속성과 연관 관계가 JSON으로 변환됩니다. PHP가 지원하는 JSON 인코딩 옵션을 인수로 전달할 수도 있습니다.
use App\Models\User;
$user = User::find(1);
return $user->toJson();
return $user->toJson(JSON_PRETTY_PRINT);모델이나 컬렉션을 문자열로 캐스팅하면 자동으로 toJson이 호출됩니다.
return (string) User::find(1);모델과 컬렉션은 문자열로 캐스팅될 때 JSON으로 변환되므로, 라우트나 컨트롤러에서 Eloquent 객체를 직접 반환해도 됩니다. Laravel이 자동으로 JSON으로 직렬화해 응답합니다.
Route::get('/users', function () {
return User::all();
});연관 관계 직렬화
Eloquent 모델이 JSON으로 변환될 때, 이미 로드된 연관 관계는 자동으로 JSON 객체의 속성으로 포함됩니다. 또한, Eloquent 연관 관계 메서드는 camelCase로 정의되지만, JSON에서는 snake_case 키로 출력됩니다.
JSON에서 특정 속성 숨기기
비밀번호처럼 외부에 노출되어서는 안 되는 속성을 배열이나 JSON 변환 결과에서 제외하고 싶을 때는 모델에 $hidden 프로퍼티를 정의합니다. 이 배열에 나열된 속성은 직렬화 결과에 포함되지 않습니다.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 직렬화 시 숨길 속성 목록
*
* @var array<string>
*/
protected $hidden = ['password'];
}NOTE
연관 관계를 숨기려면 해당 연관 관계의 메서드 이름을 $hidden 배열에 추가하면 됩니다.
반대로, 노출할 속성만 명시적으로 지정하고 싶다면 $visible 프로퍼티를 사용합니다. $visible 배열에 포함되지 않은 속성은 배열이나 JSON 변환 시 모두 숨겨집니다.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 배열 변환 시 노출할 속성 목록
*
* @var array
*/
protected $visible = ['first_name', 'last_name'];
}특정 인스턴스에서 임시로 가시성 변경하기
특정 모델 인스턴스에서 일시적으로 숨겨진 속성을 노출하려면 makeVisible 또는 mergeVisible 메서드를 사용합니다. 두 메서드 모두 모델 인스턴스를 반환합니다.
return $user->makeVisible('attribute')->toArray();
return $user->mergeVisible(['name', 'email'])->toArray();반대로, 평소에는 노출되는 속성을 일시적으로 숨기려면 makeHidden 또는 mergeHidden 메서드를 사용합니다.
return $user->makeHidden('attribute')->toArray();
return $user->mergeHidden(['name', 'email'])->toArray();visible과 hidden 설정 전체를 임시로 덮어쓰려면 각각 setVisible과 setHidden 메서드를 사용합니다.
return $user->setVisible(['id', 'name'])->toArray();
return $user->setHidden(['email', 'password', 'remember_token'])->toArray();JSON에 값 추가하기
모델을 배열이나 JSON으로 변환할 때, 데이터베이스 컬럼에는 없지만 추가로 포함하고 싶은 값이 있을 수 있습니다. 이럴 때는 먼저 해당 값에 대한 접근자(accessor)를 정의합니다.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 사용자가 관리자인지 확인
*/
protected function isAdmin(): Attribute
{
return new Attribute(
get: fn () => 'yes',
);
}
}이 접근자를 항상 직렬화 결과에 포함하려면 모델의 $appends 프로퍼티에 속성 이름을 추가합니다. 접근자 메서드는 camelCase로 정의하지만, $appends에는 snake_case로 등록합니다.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 배열 변환 시 항상 포함할 접근자 목록
*
* @var array
*/
protected $appends = ['is_admin'];
}$appends에 등록된 속성은 배열과 JSON 변환 결과 모두에 포함되며, 모델에 설정된 $visible 및 $hidden 규칙도 동일하게 적용됩니다.
런타임에 동적으로 추가하기
런타임에 특정 모델 인스턴스에 추가 속성을 붙이려면 append 또는 mergeAppends 메서드를 사용합니다. setAppends를 사용하면 기존 설정을 완전히 대체할 수 있습니다.
return $user->append('is_admin')->toArray();
return $user->mergeAppends(['is_admin', 'status'])->toArray();
return $user->setAppends(['is_admin'])->toArray();추가된 속성을 모두 제거하려면 withoutAppends 메서드를 사용합니다.
return $user->withoutAppends()->toArray();날짜 직렬화
기본 날짜 형식 커스터마이징
serializeDate 메서드를 오버라이드하면 배열이나 JSON으로 변환할 때 사용되는 기본 날짜 형식을 변경할 수 있습니다. 이 설정은 데이터베이스에 저장되는 날짜 형식에는 영향을 주지 않습니다.
/**
* 배열/JSON 직렬화를 위한 날짜 형식 지정
*/
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d');
}속성별 날짜 형식 커스터마이징
특정 날짜 속성의 직렬화 형식을 개별적으로 지정하려면 모델의 캐스트 선언에서 날짜 형식을 명시합니다.
protected function casts(): array
{
return [
'birthday' => 'date:Y-m-d',
'joined_at' => 'datetime:Y-m-d H:00',
];
}