跳轉至內容

Eloquent: 序列化

簡介

在使用 Laravel 構建 API 時,你通常需要將模型和關聯轉換為陣列或 JSON。Eloquent 包含了一些便捷的方法來執行這些轉換,同時也允許你控制哪些屬性應包含在模型的序列化表示中。

如需更強大的 Eloquent 模型和集合 JSON 序列化處理方式,請查閱 Eloquent API 資源 文件。

序列化模型與集合

序列化為陣列

要將模型及其已載入的 關聯 轉換為陣列,你應該使用 toArray 方法。該方法是遞迴的,因此所有屬性和所有關聯(包括關聯的關聯)都將被轉換為陣列。

1use App\Models\User;
2 
3$user = User::with('roles')->first();
4 
5return $user->toArray();

attributesToArray 方法可用於將模型的屬性轉換為陣列,但不包含其關聯。

1$user = User::first();
2 
3return $user->attributesToArray();

你也可以透過在集合例項上呼叫 toArray 方法,將整個 模型集合 轉換為陣列。

1$users = User::all();
2 
3return $users->toArray();

序列化為 JSON

要將模型轉換為 JSON,你應該使用 toJson 方法。與 toArray 一樣,toJson 方法也是遞迴的,因此所有屬性和關聯都會被轉換為 JSON。你還可以指定 PHP 支援的 任何 JSON 編碼選項。

1use App\Models\User;
2 
3$user = User::find(1);
4 
5return $user->toJson();
6 
7return $user->toJson(JSON_PRETTY_PRINT);

或者,你也可以將模型或集合強制轉換為字串,這會自動呼叫該模型或集合上的 toJson 方法。

1return (string) User::find(1);

由於模型和集合在強制轉換為字串時會轉換為 JSON,因此你可以直接從應用程式的路由或控制器中返回 Eloquent 物件。當從路由或控制器返回 Eloquent 模型和集合時,Laravel 會自動將其序列化為 JSON。

1Route::get('/users', function () {
2 return User::all();
3});

關聯關係

當 Eloquent 模型轉換為 JSON 時,其已載入的關聯將自動作為屬性包含在 JSON 物件中。此外,雖然 Eloquent 關聯方法是使用“駝峰命名法”定義的,但關聯的 JSON 屬性名稱將是“蛇形命名法”。

從 JSON 中隱藏屬性

有時你可能希望限制模型陣列或 JSON 表示中包含的屬性(例如密碼)。為此,你可以在模型中使用 $hidden 屬性。列在 $hidden 屬性中的屬性將不會包含在模型的序列化表示中。

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Attributes\Hidden;
6use Illuminate\Database\Eloquent\Model;
7 
8#[Hidden(['password'])]
9class User extends Model
10{
11 // ...
12}

要隱藏關聯,請將關聯的方法名稱新增到你的 Eloquent 模型的 $hidden 屬性中。

或者,你可以使用 $visible 屬性來定義一個“允許列表”,指定哪些屬性應該包含在模型的陣列和 JSON 表示中。當模型轉換為陣列或 JSON 時,所有不在 $visible 屬性中的屬性都將被隱藏。

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Attributes\Visible;
6use Illuminate\Database\Eloquent\Model;
7 
8#[Visible(['first_name', 'last_name'])]
9class User extends Model
10{
11 // ...
12}

臨時修改屬性可見性

如果你想讓某個模型例項中通常被隱藏的屬性可見,可以使用 makeVisiblemergeVisible 方法。makeVisible 方法會返回模型例項。

1return $user->makeVisible('attribute')->toArray();
2 
3return $user->mergeVisible(['name', 'email'])->toArray();

同樣,如果你想隱藏一些通常可見的屬性,可以使用 makeHiddenmergeHidden 方法。

1return $user->makeHidden('attribute')->toArray();
2 
3return $user->mergeHidden(['name', 'email'])->toArray();

如果你希望臨時覆蓋所有可見或隱藏的屬性,可以分別使用 setVisiblesetHidden 方法。

1return $user->setVisible(['id', 'name'])->toArray();
2 
3return $user->setHidden(['email', 'password', 'remember_token'])->toArray();

追加值到 JSON

有時,在將模型轉換為陣列或 JSON 時,你可能希望新增資料庫中沒有對應列的屬性。為此,首先為該值定義一個 訪問器

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Casts\Attribute;
6use Illuminate\Database\Eloquent\Model;
7 
8class User extends Model
9{
10 /**
11 * Determine if the user is an administrator.
12 */
13 protected function isAdmin(): Attribute
14 {
15 return new Attribute(
16 get: fn () => 'yes',
17 );
18 }
19}

如果你希望訪問器始終追加到模型的陣列和 JSON 表示中,可以使用模型上的 $appends 屬性。請注意,屬性名稱通常使用其“蛇形命名法”的序列化表示來引用,即使訪問器的 PHP 方法是使用“駝峰命名法”定義的。

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Attributes\Appends;
6use Illuminate\Database\Eloquent\Model;
7 
8#[Appends(['is_admin'])]
9class User extends Model
10{
11 // ...
12}

一旦屬性被新增到 $appends 列表中,它就會包含在模型的陣列和 JSON 表示中。$appends 陣列中的屬性同樣會遵循模型上配置的 visiblehidden 設定。

執行時追加

在執行時,你可以指示模型例項使用 appendmergeAppends 方法追加額外屬性。或者,你可以使用 setAppends 方法為給定的模型例項覆蓋整個追加屬性陣列。

1return $user->append('is_admin')->toArray();
2 
3return $user->mergeAppends(['is_admin', 'status'])->toArray();
4 
5return $user->setAppends(['is_admin'])->toArray();

同樣,如果你想從模型中刪除所有追加的屬性,可以使用 withoutAppends 方法。

1return $user->withoutAppends()->toArray();

日期序列化

自定義預設日期格式

你可以透過重寫 serializeDate 方法來自定義預設的序列化格式。此方法不會影響日期在資料庫中的儲存格式。

1/**
2 * Prepare a date for array / JSON serialization.
3 */
4protected function serializeDate(DateTimeInterface $date): string
5{
6 return $date->format('Y-m-d');
7}

自定義單個屬性的日期格式

你可以在模型的 型別轉換宣告 中指定日期格式,從而自定義單個 Eloquent 日期屬性的序列化格式。

1protected function casts(): array
2{
3 return [
4 'birthday' => 'date:Y-m-d',
5 'joined_at' => 'datetime:Y-m-d H:00',
6 ];
7}