緣起
后端開(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_at
和 updated_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
屬性.
- 如果要隱藏整張關(guān)聯(lián)表的字段畸裳,需要在
$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()
方法即可.
參考文章
- Laravel 源碼: .../vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
- laravel--模型中各種屬性詳解
- Laravel 5.1 文檔攻略 —— Eloquent: 讀取器和修飾器
- Laravel 5.1 文檔攻略 —— Eloquent:模型對(duì)象序列化
- nesbot/carbon - A simple API extension for DateTime
文章歷史
- 2017/04/30 (第一次發(fā)布)
- 2017/05/03 潤(rùn)色
- 2017/06/03 潤(rùn)色
- 2017/06/14 潤(rùn)色
如果我的文章對(duì)你有用, 希望給些改進(jìn)的建議, 或者打個(gè)"喜歡" _