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 Model10{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 Model10{11 // ...12}
临时修改属性可见性
如果你想让某个模型实例中通常被隐藏的属性可见,可以使用 makeVisible 或 mergeVisible 方法。makeVisible 方法会返回模型实例。
1return $user->makeVisible('attribute')->toArray();2 3return $user->mergeVisible(['name', 'email'])->toArray();
同样,如果你想隐藏一些通常可见的属性,可以使用 makeHidden 或 mergeHidden 方法。
1return $user->makeHidden('attribute')->toArray();2 3return $user->mergeHidden(['name', 'email'])->toArray();
如果你希望临时覆盖所有可见或隐藏的属性,可以分别使用 setVisible 和 setHidden 方法。
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(): Attribute14 {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 Model10{11 // ...12}
一旦属性被添加到 $appends 列表中,它就会包含在模型的数组和 JSON 表示中。$appends 数组中的属性同样会遵循模型上配置的 visible 和 hidden 设置。
运行时追加
在运行时,你可以指示模型实例使用 append 或 mergeAppends 方法追加额外属性。或者,你可以使用 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): string5{6 return $date->format('Y-m-d');7}
自定义单个属性的日期格式
你可以在模型的 类型转换声明 中指定日期格式,从而自定义单个 Eloquent 日期属性的序列化格式。
1protected function casts(): array2{3 return [4 'birthday' => 'date:Y-m-d',5 'joined_at' => 'datetime:Y-m-d H:00',6 ];7}