跳到主要內容

Eloquent 序列化

📝 此頁面為 Laravel 官方文檔的繁體中文翻譯。查看原始英文版本

Eloquent:序列化

簡介

使用 Laravel 建立 API 時,您經常需要將模型和關係轉換為陣列或 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 一樣,toJson 方法是遞迴的,因此所有屬性和關係都將被轉換為 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 將自動將您的 Eloquent 模型和集合序列化為 JSON:

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

關係

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

從 JSON 中隱藏屬性

有時您可能希望限制包含在模型的陣列或 JSON 表示中的屬性,例如密碼。為此,您可以在模型上使用 Hidden 屬性。在 Hidden 屬性中列出的屬性將不會包含在模型的序列化表示中:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Model;

#[Hidden(['password'])]
class User extends Model
{
    // ...
}

[!NOTE] 要隱藏關係,請將關係的方法名稱添加到 Eloquent 模型的 Hidden 屬性中。

或者,您可以使用 Visible 屬性來定義應包含在模型的陣列和 JSON 表示中的屬性的「允許清單」。不在 Visible 屬性中的所有屬性在模型轉換為陣列或 JSON 時都將被隱藏:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Visible;
use Illuminate\Database\Eloquent\Model;

#[Visible(['first_name', 'last_name'])]
class User extends Model
{
    // ...
}

暫時修改屬性可見性

如果您希望在給定模型實例上使某些通常隱藏的屬性可見,可以使用 makeVisiblemergeVisible 方法。makeVisible 方法返回模型實例:

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

return $user->mergeVisible(['name', 'email'])->toArray();

同樣地,如果您希望隱藏某些通常可見的屬性,可以使用 makeHiddenmergeHidden 方法:

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

return $user->mergeHidden(['name', 'email'])->toArray();

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

return $user->setVisible(['id', 'name'])->toArray();

return $user->setHidden(['email', 'password', 'remember_token'])->toArray();

向 JSON 追加值

偶爾,在將模型轉換為陣列或 JSON 時,您可能希望添加在資料庫中沒有相應列的屬性。為此,首先為該值定義一個存取器

<?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',
        );
    }
}

如果您希望存取器始終追加到模型的陣列和 JSON 表示中,可以在模型上使用 Appends 屬性。請注意,即使存取器的 PHP 方法是使用「駝峰式」定義的,屬性名稱通常也是使用其「蛇形命名」的序列化表示來引用的:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Model;

#[Appends(['is_admin'])]
class User extends Model
{
    // ...
}

一旦將屬性添加到 appends 列表中,它將同時包含在模型的陣列和 JSON 表示中。appends 陣列中的屬性也將尊重模型上配置的 visiblehidden 設定。

在運行時追加

在運行時,您可以使用 appendmergeAppends 方法指示模型實例追加額外的屬性。或者,您可以使用 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 序列化。
 */
protected function serializeDate(DateTimeInterface $date): string
{
    return $date->format('Y-m-d');
}

為每個屬性自訂日期格式

您可以透過在模型的類型轉換宣告中指定日期格式來自訂個別 Eloquent 日期屬性的序列化格式:

protected function casts(): array
{
    return [
        'birthday' => 'date:Y-m-d',
        'joined_at' => 'datetime:Y-m-d H:00',
    ];
}