Skip to content

Eloquent 序列化

介绍

使用 Laravel 构建 API 时,您通常需要将模型和关系转换为数组或 JSON。Eloquent 包括进行这些转换的便捷方法,以及控制模型的序列化表示中包含哪些属性。

NOTE

有关处理 Eloquent 模型和集合 JSON 序列化的更强大方法,请查看有关 Eloquent API 资源的文档。

序列化模型和集合

序列化为数组

要将模型及其加载的关系转换为数组,您应该使用 toArray 方法。这个方法是递归的,所以所有的 attribute 和所有 relations (包括关系的关系) 都会被转换成数组:

php
    use App\Models\User;

    $user = User::with('roles')->first();

    return $user->toArray();

attributesToArray 方法可用于将模型的属性转换为数组,但不能将其关系转换为数组:

php
    $user = User::first();

    return $user->attributesToArray();

您还可以通过在集合实例上调用 toArray 方法将整个模型集合转换为数组:

php
    $users = User::all();

    return $users->toArray();

序列化 JSON

要将模型转换为 JSON,您应该使用 toJson 方法。与 toArray 一样,toJson 方法是递归的,因此所有属性和关系都将转换为 JSON。您还可以指定 PHP 支持的任何 JSON 编码选项:

php
    use App\Models\User;

    $user = User::find(1);

    return $user->toJson();

    return $user->toJson(JSON_PRETTY_PRINT);

或者,你可以将模型或集合强制转换为字符串,这将自动调用模型或集合上的 toJson 方法:

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

由于模型和集合在转换为字符串时会转换为 JSON,因此您可以直接从应用程序的路由或控制器返回 Eloquent 对象。Laravel 会在从路由或控制器返回 Eloquent 模型和集合时自动将它们序列化为 JSON:

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

Relationships

当 Eloquent 模型转换为 JSON 时,其加载的关系将自动作为属性包含在 JSON 对象中。此外,尽管 Eloquent 关系方法是使用 “驼峰式大小写” 方法名称定义的,但关系的 JSON 属性将是 “snake case”。

在 JSON 中隐藏属性

有时您可能希望限制模型数组或 JSON 表示中包含的属性,例如密码。为此,请向模型添加 $hidden 属性。$hidden 属性的数组中列出的属性将不包含在模型的序列化表示中:

php
    <?php

    namespace App\Models;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model
    {
        /**
         * 数组应该隐藏的属性。
         *
         * @var array
         */
        protected $hidden = ['password'];
    }

NOTE

要隐藏关系,请将关系的方法名称添加到 Eloquent 模型的 $hidden 属性中。

或者,你可以使用 visible 属性来定义一个 “allow list” 属性,这些属性应该包含在模型的数组和 JSON 表示中。当模型转换为数组或 JSON 时,$visible数组中不存在的所有属性都将被隐藏:

php
    <?php

    namespace App\Models;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model
    {
        /**
         * 数组中应该可见的属性。
         *
         * @var array
         */
        protected $visible = ['first_name', 'last_name'];
    }

临时修改属性可见性

如果你想让一些通常隐藏的属性在给定的模型实例上可见,你可以使用 makeVisible 方法。makeVisible 方法返回 model 实例:

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

同样,如果您想隐藏一些通常可见的属性,您可以使用 makeHidden 方法。

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

如果你希望临时覆盖所有 visible 或 hidden 属性,你可以分别使用 setVisiblesetHidden 方法:

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

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

将值附加到 JSON

有时,在将模型转换为数组或 JSON 时,您可能希望添加在数据库中没有相应列的属性。为此,首先为值定义一个 访问器

php
    <?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 属性中。请注意,属性名称通常使用其 “snake case” 序列化表示来引用,即使访问器的 PHP 方法是使用 “camel case” 定义的:

php
    <?php

    namespace App\Models;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model
    {
        /**
         * 要附加到模型的数组形式的访问器。
         *
         * @var array
         */
        protected $appends = ['is_admin'];
    }

将属性添加到 appends 列表后,它将包含在模型的数组和 JSON 表示形式中。appends 数组中的属性也将遵循在模型上配置的 visiblehidden 设置。

在运行时追加

在运行时,您可以指示模型实例使用 append 方法附加其他属性。或者,你可以使用 setAppends 方法来覆盖给定模型实例的整个附加属性数组:

php
    return $user->append('is_admin')->toArray();

    return $user->setAppends(['is_admin'])->toArray();

日期序列化

自定义默认日期格式

您可以通过覆盖 serializeDate 方法来自定义默认序列化格式。此方法不会影响日期的格式以存储在数据库中:

php
    /**
     * 准备数组/JSON 序列化的日期
     */
    protected function serializeDate(DateTimeInterface $date): string
    {
        return $date->format('Y-m-d');
    }

自定义每个属性的日期格式

你可以通过在模型的强制转换声明中指定日期格式来自定义单个 Eloquent 日期属性的序列化格式:

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