模型提供一些事件
如果我给所有表都添加了创建者字段(creator)
创建时应该写入该字段
使用模型类添加数据
# user 模型中重写onBeforeInsert
# 在插入前添加creator 属性
public static function onBeforeInsert(Model $model)
{
$model->creator = 6;
}
# 触发事件,插入前添加creator=6
# 如果要让所有表都添加creator字段
# 可以写一个公共model类,其继承model,在其中重写 onBeforeInsert
# 其他模型类继承该类即可
User::create(['username' => 'username_1', 'password' => 'username_1_password']);
使用db类添加数据
$time = date('Y-m-d H:i:s');
# 使用Db类,创建时间和修改时间不会自动写入
# 使用Db的创建数据,每一个地方都要手动添加creator
Db::name('user')->save(['username' => 'username_2', 'password' => 'username_2', 'created_at' => $time, 'updated_at' => $time, 'creator' => 6]);
提供修改器和获取器
以user表的电话(mobile)为例
前期功能已经开发好了
后期为了数据安全想对数据库中的数据加密(数据库中存储密文)
如果使用的是DB类,那么用到手机号的地方都要调用解密方法
新增的地方都要调用加密方法
如果使用的是模型可以增加电话获取器(返回解密后结果)
增加电话修改器(返回加密结果)
使用Db类来完成上述新增需求
# 每个新增的地方都要改
# $phone 代表电话号码
$encryptPhone = openssl_encrypt($phone, 'aes-128-cbc', 'xrx', 0, 'abc_efg_hij_klm_');
Db::name('user')->save([
'username' => 'username_db',
'password' => 'password_db',
'mobile' => $encryptPhone,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
使用Db类来完成上述查询需求
$result = Db::name('user')->find(13);
# 每个用到电话得地方都要增加解密这行
return openssl_decrypt($result['mobile'], 'aes-128-cbc', 'xrx', 0, 'abc_efg_hij_klm_');
通过修改器完成上述新增需求
# user模型中 增加mobile修改器
# 方法名称 = set + 属性名(第一个字母大写) + Attr
public function setMobileAttr($mobile)
{
return openssl_encrypt($mobile, 'aes-128-cbc', 'xrx', 0, 'abc_efg_hij_klm_');
}
# 新增,就是普通的模型保存
# $phone 电话号码
User::create([
'username' => 'username_attr',
'password' => 'password_attr',
'mobile' => $phone,
]);
通过修改器完成上述查询需求
# 增加mobile获取器
# 方法名称 = get + 属性名(第一个字母大写) + Attr
public function getMobileAttr($mobile)
{
return openssl_decrypt($mobile, 'aes-128-cbc', 'xrx', 0, 'abc_efg_hij_klm_');
}
# 查询,就是普通模型查询
$user = User::find(13);
return $user->mobile;
提供了软删除
模型提供了软删除方法
模型中使用 think\model\concern\SoftDelete 即可
如果使用Db类需要自己手动去标记数据是否删除
查询时where条件需要带上标识字段状态
使用模型则不需要关注这些,调用模型的删除方法和查询方法即可
提供了查询作用域
将一些针对某些特定业务的常用查询封装成作用域
以 user(作者表) user.score(分数) 为例
按照分数分为,青铜,白银,黄金,钻石作者
可以将其封装成作用域,上层调用不需要关心其分数
而且通过该作用域的查询,就算以后分数分组规则改了(只需要在作用域中修改条件即可)
创建白银作者本地作用域
# 写在user模型中
# 本地作用域命名规范 scope + 作用域名称
# 白银作者分数[2000,3000]
public function scopeAg($query){
$query->whereBetween('score', [2000, 3000]);
}
使用作用域查找白银作者
# 通过scope($scope)
# $scope 过滤器名称 使用单个过滤器传string
$users = User::scope(['Ag'])->select();
# 使用多个过滤器传array
# 查找满足特定年龄的白银作者
$users = User::scope(['Ag', 'Age'])->select();
全局作用域
就是设置默认的作用域,不需要像本地作用域一样显式调用
假设你的订单数量到达1000万左右,这是查询比较慢了
这时你的Leader和你说只能查三个月内的
这时就可以通过全局作用域解决这个问题
创建order全局作用域
# 声明和声明本地作用域一样
# 这里在 Order模型中声明
public function ScopeBase($query)
{
# 我知道800万条之前的都是大于现在三个月的时间(提高查询速度)
# 时间应该动态去算,这里就假设今天是2022-04-29,那么三个月前就是2022-01-29
$query->where('id', '>', 8000000)->where('created_at', '>=', '2022-01-29');
}
# 只不过需要将作用域添加到 model globalScope属性之中
# 这里添加到Order模型 的 globalScope属性之中
protected $globalScope = ['base'];
全局作用域使用
# 和普通的模型查询一样
$order = new Order();
# SELECT * FROM `order` WHERE `id` > 8000000 AND `created_at` >= '2022-01-29' AND `order_number` = '996_icu' LIMIT 1
$order->where('order_number', 'hello_world')->find();