Eloquent:序列化

簡介

在使用 Laravel 製作 API 時,我們常常會需要將 Model 於關聯轉換為陣列或 JSON。Eloquent 中包含了一些用來進行這些轉換的方便方法,我們也能控制哪些屬性要被包含在 Model 序列化呈現中。

lightbulb

若想瞭解有關控制 Eloquent Model 與 JSON 序列化更強健的方法,請參考 Eloquent API 資源說明文件。

序列化 Model 與 Collection

序列化為陣列

若要將 Model 與其已載入的關聯轉換為陣列,可使用 toArray 方法。該方法是遞歸的,因此所有的屬性與所有的關聯(還有關聯的關聯)都會被轉換為陣列:

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

attributesToArray 方法可用來將 Model 的屬性轉換為陣列,但不轉換關聯:

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

也可以使用 Collection 實體上的 toArray 方法來將整個包含 Model 的 Collection 都轉換為陣列:

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

序列化為 JSON

若要將 Model 轉換為 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);
1use App\Models\User;
2 
3$user = User::find(1);
4 
5return $user->toJson();
6 
7return $user->toJson(JSON_PRETTY_PRINT);

或者,我們也可以將 Model 或 Collection 型別轉換成字串,這麼做會自動呼叫 Model 或 Collection 上的 toJson 方法:

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

由於 Model 與 Collection 在轉換為字串時會被轉換成 JSON,因此,我們可以直接在路由或 Controller 內回傳 Eloquent 物件。當這些 Eloquent Model 與 Collection 被從路由或 Controller 回傳時,Laravel 會自動將他們序列化成 JSON:

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

關聯

當 Eloquent Model 被轉換為 JSON 時,Eloquent 會自動將所有已載入的關聯以屬性的方式包含在 JSON 內。此外,雖然 Eloquent 屬性是使用「駝峰命名法 (camelCase)」作為方法名稱定義的,但關聯的 JSON 屬性會是「蛇形命名法 (snake_case)」。

從 JSON 中隱藏屬性

有時候,我們可能會讓如密碼等屬性不要被包含在 Model 的陣列或 JSON 呈現上。為此,請在 Model 中加上一個 $hidden 屬性。列在 $hidden 屬性陣列中的屬性將不會被包含在 Model 的序列化呈現中:

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Model;
6 
7class User extends Model
8{
9 /**
10 * The attributes that should be hidden for arrays.
11 *
12 * @var array
13 */
14 protected $hidden = ['password'];
15}
1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Model;
6 
7class User extends Model
8{
9 /**
10 * The attributes that should be hidden for arrays.
11 *
12 * @var array
13 */
14 protected $hidden = ['password'];
15}
lightbulb

若要隱藏關聯,請將關聯的方法名稱加到 Eloquent Model 的 $hidden 屬性內。

或者,我們也可以使用 visible 屬性來定義一個「允許列表」,代表要被包含在 Model 之陣列與 JSON 呈現的屬性。當 Model 被轉換為陣列或 JSON 時,所有不在 $visible 陣列內的屬性都會被隱藏:

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Model;
6 
7class User extends Model
8{
9 /**
10 * The attributes that should be visible in arrays.
11 *
12 * @var array
13 */
14 protected $visible = ['first_name', 'last_name'];
15}
1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Model;
6 
7class User extends Model
8{
9 /**
10 * The attributes that should be visible in arrays.
11 *
12 * @var array
13 */
14 protected $visible = ['first_name', 'last_name'];
15}

暫時修改屬性的能見度

對於某個 Model 實體,若我們想讓一些平常都是隱藏的屬性顯示出來,可以使用 makeVisible 方法。makeVisible 方法會回傳 Model 的實體:

1return $user->makeVisible('attribute')->toArray();
1return $user->makeVisible('attribute')->toArray();

同樣的,若想隱藏一些平常顯示的屬性,可以使用 makeHidden 方法。

1return $user->makeHidden('attribute')->toArray();
1return $user->makeHidden('attribute')->toArray();

若想暫時複寫所有 Visible 或 Hidden 屬性的話,可使用對應的 setVisiblesetHidden 方法:

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

將值附加到 JSON

有時候,在將 Model 轉換為陣列或 JSON 時,我們可能會想新增一些資料庫中沒有對應欄位的屬性。為此,請先為該值定義一個 Accessor

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 * @return \Illuminate\Database\Eloquent\Casts\Attribute
14 */
15 protected function isAdmin(): Attribute
16 {
17 return new Attribute(
18 get: fn () => 'yes',
19 );
20 }
21}
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 * @return \Illuminate\Database\Eloquent\Casts\Attribute
14 */
15 protected function isAdmin(): Attribute
16 {
17 return new Attribute(
18 get: fn () => 'yes',
19 );
20 }
21}

建立好 Accessor 後,請將屬性名稱加到 Model 中的 appends 屬性。請注意,屬性名稱一般在序列化呈現中都使用「蛇形命名法 (snake_case)」,但 Accessor 的 PHP 方法是使用「駝峰命名法 (camelCase)」定義的:

1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Model;
6 
7class User extends Model
8{
9 /**
10 * The accessors to append to the model's array form.
11 *
12 * @var array
13 */
14 protected $appends = ['is_admin'];
15}
1<?php
2 
3namespace App\Models;
4 
5use Illuminate\Database\Eloquent\Model;
6 
7class User extends Model
8{
9 /**
10 * The accessors to append to the model's array form.
11 *
12 * @var array
13 */
14 protected $appends = ['is_admin'];
15}

將屬性加到 appends 列表後,該屬性就會被加到 Model 的陣列與 JSON 呈現中。在 appends 陣列中的屬性也會尊重 Model 上的 visiblehidden 設定。

在執行階段附加

在執行階段時,我們可以使用 append 方法來讓 Model 實體附加額外的屬性。或者,我們也可以使用 setAppends 方法來複寫給定 Model 實體上的整個附加屬性陣列:

1return $user->append('is_admin')->toArray();
2 
3return $user->setAppends(['is_admin'])->toArray();
1return $user->append('is_admin')->toArray();
2 
3return $user->setAppends(['is_admin'])->toArray();

日期的序列化

自訂預設的日期格式

複寫 serializeDate 方法即可定義預設的序列化方法。該方法並不會影響日期儲存到資料庫時的格式化方法:

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

為個別屬性自訂日期格式

可以在 Model 的型別轉換宣告中指定日期格式,來為個別 Eloquent 日期屬性自訂序列化格式:

1protected $casts = [
2 'birthday' => 'date:Y-m-d',
3 'joined_at' => 'datetime:Y-m-d H:00',
4];
1protected $casts = [
2 'birthday' => 'date:Y-m-d',
3 'joined_at' => 'datetime:Y-m-d H:00',
4];
翻譯進度
100% 已翻譯
更新時間:
2023年2月11日 上午10:27:00 [世界標準時間]
翻譯人員:
  • cornch
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.