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_atupdated_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() 方法即可.


参考文章


文章历史

  • 2017/04/30 (第一次发布)
  • 2017/05/03 润色
  • 2017/06/03 润色
  • 2017/06/14 润色

如果我的文章对你有用, 希望给些改进的建议, 或者打个"喜欢" _

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容