这是一个基于 ThinkPHP 8 的  User  模型最佳实践完整示例。这个示例综合了软删除、模型事件、修改器/获取器以及模型关联,展示了如何将数据逻辑与业务逻辑优雅地分离。

1. 模型定义 ( app/model/User.php )

<?php
declare(strict_types=1);

namespace app\model;

use think\Model;
use think\model\concern\SoftDelete;

class User extends Model
{
// 1. 引入软删除 Trait
use SoftDelete;
protected $deleteTime = 'delete_time'; // 软删除字段
protected $defaultSoftDelete = 0; // 未删除时的默认值

// 2. 定义模型关联(一对多:用户 -> 文章)
public function articles()
{
return $this->hasMany(Article::class, 'user_id', 'id');
}

// 3. 模型事件:在插入数据库前自动处理逻辑
protected static function onBeforeInsert($user)
{
// 自动将明文密码进行哈希加密
if (!empty($user->password)) {
$user->password = password_hash($user->password, PASSWORD_BCRYPT);
}
}

// 4. 修改器(Mutator):写入数据库时自动处理
// 当调用 $user->phone = '13800138000' 时触发
public function setPhoneAttr($value)
{
// 这里可以做手机号去空格或格式校验
return trim($value);
}

// 5. 获取器(Accessor):读取数据时自动处理
// 当访问 $user->status_text 时触发
public function getStatusTextAttr($value, $data)
{
$statusMap = [0 => '禁用', 1 => '正常'];
return $statusMap[$data['status']] ?? '未知';
}
}

2. 控制器中的优雅调用 ( app/controller/User.php )

<?php
declare(strict_types=1);

namespace app\controller;

use app\model\User;
use think\Request;

class User
{
// 用户注册示例
public function register(Request $request)
{
// 允许写入的字段(防止非法字段注入)
$data = $request->only(['username', 'password', 'phone', 'email'], 'post');
// 触发 onBeforeInsert 事件,密码自动加密
$user = User::create($data);
return json(['code' => 200, 'msg' => '注册成功', 'data' => $user]);
}

// 获取用户详情及文章列表示例
public function read(int $id)
{
// 使用 withJoin 或 with 预加载关联数据,避免 N+1 查询问题
$user = User::with(['articles'])->find($id);

if (!$user) {
return json(['code' => 404, 'msg' => '用户不存在'], 404);
}

// 获取器自动生效:返回结果中会自动带上 status_text 字段
return json(['code' => 200, 'data' => $user]);
}

// 软删除与恢复示例
public function delete(int $id)
{
$user = User::find($id);
if ($user) {
$user->delete(); // 执行软删除(更新 delete_time 字段)
// 如果需要彻底物理删除:$user->force()->delete();
}
return json(['code' => 200, 'msg' => '删除成功']);
}
}

💡 核心设计思路总结:


职责单一:Controller 只负责接收参数和返回 JSON,所有的密码加密、字段格式化、状态映射都下沉到了 Model 中。


安全性:使用  allowField  或  only  过滤字段,结合修改器处理敏感数据。


性能优化:查询关联数据时使用  with  预加载,避免循环查库。


扩展性:如果未来需要增加“注册后自动发欢迎邮件”的逻辑,只需在  onAfterInsert  事件中追加代码,完全不用改动 Controller。