Laravel ORM Model 的预定义属性
缘起
后端开发的基本操作就是处理数据 -- "增删改查 / CURD", 而 Laravel 框架的"对象关系映射 (ORM = Object Relationship Mapping)" 为解决数据操作中的痛点和痒点提供了便捷的解决方案.
属性
$table 属性 -- 自定义关联的数据表
既然叫"对象关系映射", 则意味着有明确的对应关系和约定.
Laravel 约定数据表的表名是 Model 名的复数, 比如 User Model 对应的是 users 表, Order Model 对应的是 orders 表.
如果需要自定义, 可以通过覆写 $table
属性来指定表名:
protected $table = 'yourTableName';
$primaryKey 属性 -- 自定义主键
Laravel 约定每张表都有整型的 id
字段做为自增主键.
如果想设置其他字段做为主键,可以通过覆写 $primaryKey
属性来自定义.
protected $primaryKey = 'uid';
$timestamp 属性 -- 数据的时间戳属性
数据的可追溯性是非常重要的. 所以 Laravel 迁移文件默认带时间戳:
$table->timestamps();
所以通过迁移文件生成的数据表默认带 create_at
和 updated_at
字段, 在添加数据和更新数据时会分别自动更新这两个字段.
这两个字段是 MySQL 的 datetime
类型, 即这种样式: 2015-08-05 07:27:09
.
但是个人觉得从 MySQL 检索优化的角度来说, int
型的 Unix 时间戳比 datetime
类型速度要快, 所以这样设置:
use Illuminate\Database\Eloquent\Model;
class PosterSubScribeModel extends Model
{
protected $table = 'subscriber';
protected $guarded = [''];
/**
* 获取当前Unix时间戳
* @return int
*/
public function freshTimestamp()
{
return time();
}
/**
* 避免转换Unix时间戳为时间字符串
*
* @param \DateTime|int $value
* @return \DateTime|int
*/
public function fromDateTime($value)
{
return $value;
}
}
PS. 如果不想使用
timestamp
, 可以将其关闭:
protected $timestamps = FALSE;
$casts 属性 -- 转化数据类型
PHP 擅长处理数组, 而前后端交互通常用 JSON, 所以常见的场景是我们希望用"数组"处理数据和存储数据, 但是希望读取出来的是 JSON 格式.
这种场景下就可以使用 $casts
属性, 实现取出数据时自动转化为 JSON 数据:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $casts = [
'my_array_data' => 'json',
];
}
还有一种使用场景, 是把存储的 1 和 0, 在取出时自动转化为 true 和 false:
class User extends Model
{
protected $casts = [
'options' => 'json',
'status' => 'bool',
];
}
**注意: **
$cast
并没有真的改变存储的数据类型,而是取出数据时暂时转换成设定的数据类型;
$attributes 属性 -- 默认值
给数据库里的一个字段设置默认值.
protected $attributes = [
'goods_ids' => '[]', //可以配合 $casts, 取出数据时自动转化为 JSON
'category_ids' => '[]',
'display_order' => 0,
];
注意:
不能写成 'goods_ids' => []
. 而必须给[]
加上引号; 上次因为没有加引号, 存储数据时莫名出现多个空数据(暂时还未弄清楚原因).
$dates 属性 - 强大的时间类
时间数据经常面临"格式化"的问题, 比如"Unix时间戳"和"可读时间格式"的转化.
$date
属性可以解决这个问题.
设置成这个属性的时间数据可以自动转化为 Carbon 类的对象, 从而使用 Carbon 的方法来处理时间.
Carbon 类的方法很强大, 大家可以深入研究一下Carbon源码 或者是查看 Laravel 中的 Carbon 类 (/vendor/nesbot/carbon/src/Carbon/Carbon.php).
比如, 把"可读时间格式"(比如 2017-04-30 12:00) 转化为 "Unix 时间戳":
$model->deleted_at->timestamp
$guarded 和 $fillable 属性 -- 限制写入数据库的数据
因为 Eloquent 模型默认对批量赋值(Mass Assignment)进行保护. 这规则要求使用 create()
或者 update()
方法批量插入或者更新属性时, 需要先设置 $guarded
和 $fillable
属性.
设置后, 在批量写入数据库时, 不光会筛掉数据表没有的字段, 也会筛选掉 $guarded
和 $fillable
中限制的字段.
-
$guarded
是"黑名单", 写入这里的字段, 表示不可以被赋值; 如果所有字段都可以写入数据库, 可以这样写protected $guarded = ['']
, 表示没有需要被 "guarded/保护" 的字段. -
$fillable
是"白名单", 写入这里的字段, 表示只有在这些声明的字段可以被写入数据库;
注意:
一个 model 只能使用其中一个属性, 而不是一起使用.
一般来说, 因为这两个属性的适用场景是剔除非法赋值的数据, 所以$guarded
使用的频率高一些。
$hidden 和 $visible 属性 -- 设置数据的可见性
比如像 password 这种字段,是不希望在读取后呈现给用户看到的,那么可以把它隐藏:
- 黑名单
$hidden
的写法
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $hidden = ['password'];
}
- 白名单
$visible
的写法
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $visible = ['first_name', 'last_name']; //排除 password 字段
}
注意:
- 和
$guarded
&$fillable
属性一样, 一个 model 只能使用$hidden
和$visible
其中一个属性, 而不是同时使用.
一般来说, 由于这两个属性的适用场景是"隐藏数据", 所以$hidden
使用的频率高一些。 - 对于"关联查询"
- 如果要隐藏整张关联表的字段,需要在
$hidden
中填写"表间关系的方法"(比如hasManyPost
) - 如果要隐藏关联表里的部分字段,则需要到关联表的 model 里去设置
$hidden / $visible
属性.
- 如果要隐藏整张关联表的字段,需要在
$appends 属性 -- 添加属性
开发 API 接口时, 前端经常会要求提供一些数据表没有的字段, 这时候, 就需要使用 $appends
属性了. 在查询数据库返回的数据中, 手动增加新的数据:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function getIsAdminAttribute()
{
return 'yes';
}
protected $appends = ['is_admin'];
}
这时, 查询 users 表的数据时, 就多了一个 is_admin
的数据.
$deleted_at 属性 -- 软删除
数据是宝贵的, 而硬盘存储的成本非常低廉, 所以删除数据时一般只是添加删除标识而并不真的删除数据.
Laravel 提供了"软删除"方案, 使用 deleted_at
字段保存数据的删除时间. 查询数据时, 被软删除的数据将会自动从查询结果中排除.
想要使用"软删除", 需要这样设置:
- 1.创建数据表时在"迁移文件"中加入
deleted_at
字段:
public function up()
{
Schema::table('flights', function ($table) {
$table->softDeletes();
});
}
或者是创建迁移文件在已有的数据表中添加 deleted_at
字段:
public function up()
{
Schema::table('poster', function (Blueprint $table) {
$table->integer('deleted_at')->nullable()->comment('删除时间');
});
}
public function down()
{
Schema::table('poster', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
}
- 2.引入
SoftDeletes
的 trait, 并声明deleted_at
字段是$dates
属性:
namespace App;
use app\common\models\BaseModel;
use Illuminate\Database\Eloquent\SoftDeletes;
class Poster extends BaseModel
{
use SoftDeletes;
protected $dates = ['deleted_at'];
}
如果想要查询出这些被删除的数据时, 只要加上 withTrashed()
方法即可.
参考文章
- Laravel 源码: .../vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
- laravel--模型中各种属性详解
- Laravel 5.1 文档攻略 —— Eloquent: 读取器和修饰器
- Laravel 5.1 文档攻略 —— Eloquent:模型对象序列化
- nesbot/carbon - A simple API extension for DateTime
文章历史
- 2017/04/30 (第一次发布)
- 2017/05/03 润色
- 2017/06/03 润色
- 2017/06/14 润色
如果我的文章对你有用, 希望给些改进的建议, 或者打个"喜欢" _