Eloquent: 修改器和类型转换
简介
访问器、修改器和属性类型转换允许你在检索或设置模型实例上的 Eloquent 属性值时对其进行转换。例如,你可能希望使用 Laravel 加密器在值存储到数据库时对其进行加密,然后在 Eloquent 模型上访问该属性时自动解密。或者,你可能希望在通过 Eloquent 模型访问时将存储在数据库中的 JSON 字符串转换为数组。
访问器和修改器
定义访问器
访问器在访问 Eloquent 属性值时对其进行转换。要定义访问器,请在模型上创建一个受保护的方法来表示可访问的属性。此方法名应对应于适用的真实底层模型属性/数据库列的「驼峰命名」表示。
在此示例中,我们将为 first_name 属性定义一个访问器。当尝试检索 first_name 属性的值时,访问器将被 Eloquent 自动调用。所有属性访问器/修改器方法必须声明 Illuminate\Database\Eloquent\Casts\Attribute 的返回类型提示:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 获取用户的名字。
*/
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
);
}
}所有访问器方法返回一个 Attribute 实例,该实例定义如何访问属性以及可选地如何修改属性。在此示例中,我们只定义如何访问属性。为此,我们将 get 参数提供给 Attribute 类构造函数。
如你所见,列的原始值被传递给访问器,允许你操作并返回该值。要访问访问器的值,你可以简单地访问模型实例上的 first_name 属性:
use App\Models\User;
$user = User::find(1);
$firstName = $user->first_name;NOTE
如果你希望将这些计算值添加到模型的数组/JSON 表示中,你需要追加它们。
从多个属性构建值对象
有时你的访问器可能需要将多个模型属性转换为单个「值对象」。为此,你的 get 闭包可以接受 $attributes 的第二个参数,该参数将自动提供给闭包,并包含模型所有当前属性的数组:
use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;
/**
* 与用户的地址交互。
*/
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
);
}访问器缓存
当从访问器返回值对象时,对值对象所做的任何更改将在保存模型之前自动同步回模型。这是可能的,因为 Eloquent 保留访问器返回的实例,以便它可以在每次调用访问器时返回相同的实例: