ThinkPHP5的模型层是框架最强大的部分之一,但很多开发者只把它当作简单的增删改查工具。掌握一些进阶技巧,能让你的代码更简洁、性能更好。本文分享几个实战中高频使用的模型技巧。
一、善用模型事件与自动时间戳
模型事件可以在数据写入前后自动执行逻辑,避免在控制器里写重复代码。例如自动记录创建时间和更新时间:
class User extends Model
{
protected $autoWriteTimestamp = 'datetime';
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
protected static function init()
{
self::beforeInsert(function ($user) {
$user->password = md5($user->password);
});
self::afterDelete(function ($user) {
// 删除关联数据
$user->profile()->delete();
});
}
}注意:init是静态方法,在模型首次实例化时执行一次,适合注册事件。如果事件逻辑复杂,建议使用观察者类。
二、查询作用域让链式调用更优雅
把常用查询条件封装成作用域方法,可以大幅减少重复代码。例如只查询已审核的文章:
class Article extends Model
{
public function scopePublished($query)
{
return $query->where('status', 1)->where('publish_time', '<=', time());
}
}
// 使用
Article::published()->order('id', 'desc')->limit(10)->select();作用域支持参数传递,例如scopeCategory($query, $id),调用时写Article::category(3)即可。这比在控制器里拼where条件清晰得多。
三、关联模型的预载入与懒加载
N+1查询是性能杀手。ThinkPHP5的with方法可以预载入关联数据,一次查询搞定:
// 不推荐:循环中查询,N+1问题
$articles = Article::all();
foreach ($articles as $article) {
echo $article->user->name;
}
// 推荐:预载入
$articles = Article::with('user')->select();
foreach ($articles as $article) {
echo $article->user->name; // 不再产生额外查询
}嵌套关联用with('user.profile'),延迟预载入用load方法。如果只需要关联表的某些字段,可以写with(['user' => function($query){ $query->field('id,name'); }])。
四、软删除与数据回收
软删除不是物理删除,而是标记delete_time。开启后,默认查询会自动过滤已删除数据:
use traits\model\SoftDelete;
class Comment extends Model
{
use SoftDelete;
protected $deleteTime = 'delete_time';
}
// 只查询已删除的数据
Comment::onlyTrashed()->select();
// 恢复数据
Comment::onlyTrashed()->where('id', 1)->restore();软删除适合需要保留历史记录的场景,但要注意索引和查询条件,避免全表扫描。
五、获取器与修改器处理字段
获取器在读取字段时自动处理,修改器在写入时自动处理,让业务逻辑内聚在模型里:
class User extends Model
{
// 读取时格式化
public function getStatusTextAttr($value, $data)
{
$map = [0 => '禁用', 1 => '正常'];
return $map[$data['status']] ?? '未知';
}
// 写入时加密
public function setPasswordAttr($value)
{
return md5($value);
}
}获取器方法名规则:get + 字段名(驼峰)+ Attr。修改器同理,用set开头。
六、模型验证与自动完成
把验证规则写在模型里,配合validate方法使用,控制器只需调用$model->save($data):
class User extends Model
{
protected $validate = [
'name' => 'require|max:25',
'email' => 'email',
];
protected $auto = ['status' => 1];
}
如果验证失败,save返回false,通过$model->getError()获取错误信息。自动完成字段在写入时自动填充,减少控制器代码。
总结
- 模型事件与自动时间戳让数据操作更自动化
- 查询作用域封装常用条件,提升可读性
- 预载入关联解决N+1查询,性能提升明显
- 软删除保留数据,获取器修改器内聚业务逻辑
- 验证与自动完成让控制器更薄
这些技巧在ThinkPHP5开发中非常实用,建议在项目中逐步应用。模型用得好,代码量能减少三成以上。
评论 (0)
还没有评论,快来抢沙发吧~