Laravel ORM Model 的預(yù)定義屬性

緣起

后端開(kāi)發(fā)的基本操作就是處理數(shù)據(jù) -- "增刪改查 / CURD", 而 Laravel 框架的"對(duì)象關(guān)系映射 (ORM = Object Relationship Mapping)" 為解決數(shù)據(jù)操作中的痛點(diǎn)和癢點(diǎn)提供了便捷的解決方案.


屬性

$table 屬性 -- 自定義關(guān)聯(lián)的數(shù)據(jù)表

既然叫"對(duì)象關(guān)系映射", 則意味著有明確的對(duì)應(yīng)關(guān)系和約定.

Laravel 約定數(shù)據(jù)表的表名是 Model 名的復(fù)數(shù), 比如 User Model 對(duì)應(yīng)的是 users 表, Order Model 對(duì)應(yīng)的是 orders 表.
如果需要自定義, 可以通過(guò)覆寫(xiě) $table 屬性來(lái)指定表名:

protected $table = 'yourTableName';

$primaryKey 屬性 -- 自定義主鍵

Laravel 約定每張表都有整型的 id 字段做為自增主鍵.

如果想設(shè)置其他字段做為主鍵,可以通過(guò)覆寫(xiě) $primaryKey 屬性來(lái)自定義.

protected $primaryKey = 'uid';

$timestamp 屬性 -- 數(shù)據(jù)的時(shí)間戳屬性

數(shù)據(jù)的可追溯性是非常重要的. 所以 Laravel 遷移文件默認(rèn)帶時(shí)間戳:

$table->timestamps();

所以通過(guò)遷移文件生成的數(shù)據(jù)表默認(rèn)帶 create_atupdated_at 字段, 在添加數(shù)據(jù)和更新數(shù)據(jù)時(shí)會(huì)分別自動(dòng)更新這兩個(gè)字段.

這兩個(gè)字段是 MySQL 的 datetime 類(lèi)型, 即這種樣式: 2015-08-05 07:27:09.
但是個(gè)人覺(jué)得從 MySQL 檢索優(yōu)化的角度來(lái)說(shuō), int 型的 Unix 時(shí)間戳比 datetime 類(lèi)型速度要快, 所以這樣設(shè)置:

use Illuminate\Database\Eloquent\Model;

class PosterSubScribeModel extends Model
{
    protected $table = 'subscriber';
    protected $guarded = [''];

    /**
     * 獲取當(dāng)前Unix時(shí)間戳
     * @return int
     */
    public function freshTimestamp()
    {
        return time();
    }

    /**
     * 避免轉(zhuǎn)換Unix時(shí)間戳為時(shí)間字符串
     *
     * @param \DateTime|int $value
     * @return \DateTime|int
     */
    public function fromDateTime($value)
    {
        return $value;
    }
}

PS. 如果不想使用 timestamp, 可以將其關(guān)閉:

protected $timestamps = FALSE;

$casts 屬性 -- 轉(zhuǎn)化數(shù)據(jù)類(lèi)型

PHP 擅長(zhǎng)處理數(shù)組, 而前后端交互通常用 JSON, 所以常見(jiàn)的場(chǎng)景是我們希望用"數(shù)組"處理數(shù)據(jù)和存儲(chǔ)數(shù)據(jù), 但是希望讀取出來(lái)的是 JSON 格式.

這種場(chǎng)景下就可以使用 $casts 屬性, 實(shí)現(xiàn)取出數(shù)據(jù)時(shí)自動(dòng)轉(zhuǎn)化為 JSON 數(shù)據(jù):

namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
    protected $casts = [
        'my_array_data' => 'json',
    ];
}

還有一種使用場(chǎng)景, 是把存儲(chǔ)的 1 和 0, 在取出時(shí)自動(dòng)轉(zhuǎn)化為 true 和 false:

class User extends Model
{
    protected $casts = [
        'options' => 'json',
        'status' => 'bool',
    ];
}

**注意: **
$cast 并沒(méi)有真的改變存儲(chǔ)的數(shù)據(jù)類(lèi)型,而是取出數(shù)據(jù)時(shí)暫時(shí)轉(zhuǎn)換成設(shè)定的數(shù)據(jù)類(lèi)型;


$attributes 屬性 -- 默認(rèn)值

給數(shù)據(jù)庫(kù)里的一個(gè)字段設(shè)置默認(rèn)值.

protected $attributes = [
    'goods_ids' => '[]', //可以配合 $casts, 取出數(shù)據(jù)時(shí)自動(dòng)轉(zhuǎn)化為 JSON
    'category_ids' => '[]',
    'display_order' => 0,
];

注意:
不能寫(xiě)成 'goods_ids' => []. 而必須給[]加上引號(hào); 上次因?yàn)闆](méi)有加引號(hào), 存儲(chǔ)數(shù)據(jù)時(shí)莫名出現(xiàn)多個(gè)空數(shù)據(jù)(暫時(shí)還未弄清楚原因).


$dates 屬性 - 強(qiáng)大的時(shí)間類(lèi)

時(shí)間數(shù)據(jù)經(jīng)常面臨"格式化"的問(wèn)題, 比如"Unix時(shí)間戳"和"可讀時(shí)間格式"的轉(zhuǎn)化.

$date 屬性可以解決這個(gè)問(wèn)題.
設(shè)置成這個(gè)屬性的時(shí)間數(shù)據(jù)可以自動(dòng)轉(zhuǎn)化為 Carbon 類(lèi)的對(duì)象, 從而使用 Carbon 的方法來(lái)處理時(shí)間.

Carbon 類(lèi)的方法很強(qiáng)大, 大家可以深入研究一下Carbon源碼 或者是查看 Laravel 中的 Carbon 類(lèi) (/vendor/nesbot/carbon/src/Carbon/Carbon.php).
比如, 把"可讀時(shí)間格式"(比如 2017-04-30 12:00) 轉(zhuǎn)化為 "Unix 時(shí)間戳":

$model->deleted_at->timestamp

$guarded 和 $fillable 屬性 -- 限制寫(xiě)入數(shù)據(jù)庫(kù)的數(shù)據(jù)

因?yàn)?Eloquent 模型默認(rèn)對(duì)批量賦值(Mass Assignment)進(jìn)行保護(hù). 這規(guī)則要求使用 create() 或者 update() 方法批量插入或者更新屬性時(shí), 需要先設(shè)置 $guarded$fillable 屬性.

設(shè)置后, 在批量寫(xiě)入數(shù)據(jù)庫(kù)時(shí), 不光會(huì)篩掉數(shù)據(jù)表沒(méi)有的字段, 也會(huì)篩選掉 $guarded$fillable 中限制的字段.

  • $guarded 是"黑名單", 寫(xiě)入這里的字段, 表示不可以被賦值; 如果所有字段都可以寫(xiě)入數(shù)據(jù)庫(kù), 可以這樣寫(xiě) protected $guarded = [''], 表示沒(méi)有需要被 "guarded/保護(hù)" 的字段.
  • $fillable 是"白名單", 寫(xiě)入這里的字段, 表示只有在這些聲明的字段可以被寫(xiě)入數(shù)據(jù)庫(kù);

注意:
一個(gè) model 只能使用其中一個(gè)屬性, 而不是一起使用.
一般來(lái)說(shuō), 因?yàn)檫@兩個(gè)屬性的適用場(chǎng)景是剔除非法賦值的數(shù)據(jù), 所以$guarded 使用的頻率高一些妆兑。


$hidden 和 $visible 屬性 -- 設(shè)置數(shù)據(jù)的可見(jiàn)性

比如像 password 這種字段,是不希望在讀取后呈現(xiàn)給用戶(hù)看到的徙邻,那么可以把它隱藏:

  • 黑名單 $hidden 的寫(xiě)法
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
    protected $hidden = ['password'];
}
  • 白名單 $visible 的寫(xiě)法
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
    protected $visible = ['first_name', 'last_name']; //排除 password 字段
}

注意:

  • $guarded & $fillable 屬性一樣, 一個(gè) model 只能使用 $hidden$visible 其中一個(gè)屬性, 而不是同時(shí)使用.
    一般來(lái)說(shuō), 由于這兩個(gè)屬性的適用場(chǎng)景是"隱藏?cái)?shù)據(jù)", 所以 $hidden 使用的頻率高一些。
  • 對(duì)于"關(guān)聯(lián)查詢(xún)"
    • 如果要隱藏整張關(guān)聯(lián)表的字段畸裳,需要在 $hidden 中填寫(xiě)"表間關(guān)系的方法"(比如 hasManyPost)
    • 如果要隱藏關(guān)聯(lián)表里的部分字段缰犁,則需要到關(guān)聯(lián)表的 model 里去設(shè)置 $hidden / $visible 屬性.

$appends 屬性 -- 添加屬性

開(kāi)發(fā) API 接口時(shí), 前端經(jīng)常會(huì)要求提供一些數(shù)據(jù)表沒(méi)有的字段, 這時(shí)候, 就需要使用 $appends 屬性了. 在查詢(xún)數(shù)據(jù)庫(kù)返回的數(shù)據(jù)中, 手動(dòng)增加新的數(shù)據(jù):

namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
    public function getIsAdminAttribute()
    {
         return 'yes';
    }
     protected $appends = ['is_admin'];
}

這時(shí), 查詢(xún) users 表的數(shù)據(jù)時(shí), 就多了一個(gè) is_admin 的數(shù)據(jù).


$deleted_at 屬性 -- 軟刪除

數(shù)據(jù)是寶貴的, 而硬盤(pán)存儲(chǔ)的成本非常低廉, 所以刪除數(shù)據(jù)時(shí)一般只是添加刪除標(biāo)識(shí)而并不真的刪除數(shù)據(jù).

Laravel 提供了"軟刪除"方案, 使用 deleted_at 字段保存數(shù)據(jù)的刪除時(shí)間. 查詢(xún)數(shù)據(jù)時(shí), 被軟刪除的數(shù)據(jù)將會(huì)自動(dòng)從查詢(xún)結(jié)果中排除.

想要使用"軟刪除", 需要這樣設(shè)置:

  • 1.創(chuàng)建數(shù)據(jù)表時(shí)在"遷移文件"中加入 deleted_at 字段:
public function up()
{
    Schema::table('flights', function ($table) {
        $table->softDeletes();
    });
}

或者是創(chuàng)建遷移文件在已有的數(shù)據(jù)表中添加 deleted_at 字段:

public function up()
{
    Schema::table('poster', function (Blueprint $table) {
        $table->integer('deleted_at')->nullable()->comment('刪除時(shí)間');
    });
}

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'];
}

如果想要查詢(xún)出這些被刪除的數(shù)據(jù)時(shí), 只要加上 withTrashed() 方法即可.


參考文章


文章歷史

  • 2017/04/30 (第一次發(fā)布)
  • 2017/05/03 潤(rùn)色
  • 2017/06/03 潤(rùn)色
  • 2017/06/14 潤(rùn)色

如果我的文章對(duì)你有用, 希望給些改進(jìn)的建議, 或者打個(gè)"喜歡" _

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市怖糊,隨后出現(xiàn)的幾起案子帅容,更是在濱河造成了極大的恐慌,老刑警劉巖伍伤,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件并徘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡扰魂,警方通過(guò)查閱死者的電腦和手機(jī)麦乞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)劝评,“玉大人姐直,你說(shuō)我怎么就攤上這事〗螅” “怎么了声畏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)姻成。 經(jīng)常有香客問(wèn)我插龄,道長(zhǎng),這世上最難降的妖魔是什么科展? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任均牢,我火速辦了婚禮,結(jié)果婚禮上才睹,老公的妹妹穿的比我還像新娘膨处。我一直安慰自己见秤,他們只是感情好砂竖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布真椿。 她就那樣靜靜地躺著,像睡著了一般乎澄。 火紅的嫁衣襯著肌膚如雪突硝。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,184評(píng)論 1 308
  • 那天置济,我揣著相機(jī)與錄音解恰,去河邊找鬼。 笑死浙于,一個(gè)胖子當(dāng)著我的面吹牛护盈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羞酗,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼腐宋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了檀轨?” 一聲冷哼從身側(cè)響起胸竞,我...
    開(kāi)封第一講書(shū)人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎参萄,沒(méi)想到半個(gè)月后卫枝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讹挎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年校赤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筒溃。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡马篮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铡羡,到底是詐尸還是另有隱情积蔚,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布烦周,位于F島的核電站尽爆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏读慎。R本人自食惡果不足惜漱贱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夭委。 院中可真熱鬧幅狮,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至逐抑,卻和暖如春鸠儿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厕氨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工进每, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人命斧。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓田晚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親国葬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贤徒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容