Eloquent:修改器

简介

访问器和修改器允许您在获取或设置模型实例属性时格式化 Eloquent 属性值。例如,可能希望使用 Laravel 加密器 在将值存储到数据库时对其加密,然后在 Eloquent 模型上访问它时自动解密该属性。

除了自定义访问器和修改器外,Eloquent 还可以自动将日期字段转换为 Carbon 实例,或者甚至 将文本字段转换为 JSON

访问器 & 修改器

定义访问器

要定义访问器,可以在模型上创建一个 getFooAttribute 方法,Foo 是希望访问的字段名的「首字母大写的驼峰命名法」。在此示例中,我们会为 first_name 属性定义一个访问器。当尝试获取 first_name 属性值时,Eloquent 会自动调用访问器:

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 获取用户的名字
     *
     * @param  string  $value
     * @return string
     */
    public function getFirstNameAttribute($value)
    {
        return ucfirst($value);
    }
}

如您所见,字段的原始值被传递被访问器,允许您处理后返回值。要获取访问器的值,可以在模型实例上访问 first_name 属性:

$user = App\User::find(1);

$firstName = $user->first_name;

当然,也可以使用访问器从已有属性返回一个新的计算后的值:

/**
 * 获取用户的全名
 *
 * @return string
 */
public function getFullNameAttribute()
{
    return "{$this->first_name} {$this->last_name}";
}

如果要将这些计算后的值添加到模型的数组/JSON 形式中,需要追加它们

定义修改器

要定义修改器,可以在模型上定义一个 setFooAttribute 方法,Foo 是希望访问的字段名的「首字母大写的驼峰命名法」。同样,我们为 first_name 属性定义一个修改器。当尝试在模型上设置 first_name 属性值时,此修改器会自动被调用:

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 设置用户的名字
     *
     * @param  string  $value
     * @return void
     */
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = strtolower($value);
    }
}

修改器会接收被设置到属性的值,允许您处理此值并将处理后的值设置在 Eloquent 模型内部的 $attributes 属性上。例如,如果我们尝试将 first_name 属性设置为 Sally

$user = App\User::find(1);

$user->first_name = 'Sally';

在此实例中,会使用 Sally 的值调用 setFirstNameAttribute 函数。然后,修改器将 strtolower 函数应用于名字并在内部的 $attributes 数组中设置其结果值。

日期转换器

默认情况下,Eloquent 会将 created_atupdated_at 字段转换为 Carbon 实例,此实例继承了 PHP 的 DateTime 类并提供各种有用的方法。通过覆盖模型的 $dates 属性,可以自定义要自动转换的日期,甚至完全禁用转换:

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 要自定转换为日期的属性
     *
     * @var array
     */
    protected $dates = [
        'created_at',
        'updated_at',
        'deleted_at'
    ];
}

当字段是日期时,可以将其值设置为一个 UNIX 时间戳,日期字符串(Y-m-d),日期时间字符串,当然还可以设置成 DateTime / Carbon 实例,日期值会自动正确地存储到数据库中:

$user = App\User::find(1);

$user->deleted_at = now();

$user->save();

如上所述,当获取列在 $dates 属性中的属性时,它们会自动被转换为 Carbon 实例,允许您在属性上使用任何 Carbon 的方法:

$user = App\User::find(1);

return $user->deleted_at->getTimestamp();

日期格式

默认情况下,时间戳会被格式化为 'Y-m-d H:i:s'。如果需要自定义时间戳格式,可以在模型上设置 $dateFormat 属性。此属性决定了日期属性会怎样存储到数据库中,以及它们在模型被序列化为数组或 JSON 时的格式:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * 模型的日期字段的存储格式
     *
     * @var string
     */
    protected $dateFormat = 'U';
}

属性转换

模型上的 $casts 属性为将属性转换为常见数据类型提供了便捷的方法。$casts 属性应该是一个数组,数组的键是要转换的属性名,数组的值是希望字段转换的类型。支持的转换类型有:integerrealfloatdoublestringbooleanobjectarraycollectiondatedatetimetimestamp

例如,我们将在数据库中以整数(01)存储的 is_admin 属性转换为一个布尔值:

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 属性应该被转换的默认类型
     *
     * @var array
     */
    protected $casts = [
        'is_admin' => 'boolean',
    ];
}

现在当访问 is_admin 属性时,它将始终被转换为一个布尔值,即使在底层数据库存储的实际值是一个整数:

$user = App\User::find(1);

if ($user->is_admin) {
    //
}

数组 & JSON 转换

当字段存储序列化的 JSON 时,array 转换类型尤其有用。例如,如果数据库有一个包含序列化 JSON 数据的 JSONTEXT 类型的字段,为此字段添加 array 转换类型,当在 Eloquent 模型上访问该属性时,会自动将其反序列化为 PHP 数组:

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 属性应该被转换的默认类型
     *
     * @var array
     */
    protected $casts = [
        'options' => 'array',
    ];
}

定义转换类型后,可以访问 options 属性,它会自动从 JSON 反序列化为 PHP 数组。当设置 options 属性值时,给定的数组会自动被序列化回 JSON 进行存储:

$user = App\User::find(1);

$options = $user->options;

$options['key'] = 'value';

$user->options = $options;

$user->save();

日期转换

使用 datedatetime 转换类型时,可以指定日期的格式。此格式会在 模型被序列化为数组或 JSON 时使用:

/**
 * 属性应该被转换的默认类型
 *
 * @var array
 */
protected $casts = [
    'created_at' => 'datetime:Y-m-d',
];