thinkphp中save()不触发自动填充因跳过字段过滤,需用data()->save()或create();严格模式下未定义字段被丢弃;业务字段如create_by须用beforeinsert等事件手动赋值。

为什么 save() 不触发自动填充?
因为 ThinkPHP 的自动填充只在 create() 或模型的 data() + save() 组合中生效,而直接传数组给 save()(如 $model->save(['name' => 'x']))会跳过字段过滤和自动填充逻辑。
- 必须用
$model->data($data)->save()或先调用$model->create($data)再save() - 若启用了严格模式(
'strict' => true),未在$schema中定义的字段会被静默丢弃,导致create_time等填充字段“消失” - 注意:5.1+ 版本已废弃
create(),统一用data()+isUpdate()控制行为
如何用模型事件补全创建/更新时间?
靠 autoWriteTimestamp 配置只能写时间戳字段,但像 create_by、update_by 这类业务字段必须靠事件手动塞值。
- 在模型类中定义
protected $event = ['before_insert', 'before_update'] - 实现
beforeInsert()方法,在里面赋值:$this->create_time = date('Y-m-d H:i:s');、$this->create_by = session('user_id') ?: 0; -
beforeUpdate()中只改update_time和update_by,别碰create_time—— 否则新增记录也会被覆盖 - 事件方法返回
false可中断保存,适合做权限校验(比如禁止非管理员修改status)
autoWriteTimestamp 的坑:字符串 vs 时间戳 vs 字段名
这个配置看似简单,但填错类型或字段名就完全不生效。
- 设为
true:自动写入create_time/update_time,且默认按datetime格式('Y-m-d H:i:s') - 设为
'timestamp':写入 Unix 时间戳整数,字段类型必须是int(10),否则入库变0 - 设为
['create_time', 'update_time']:可自定义字段名,但两个字段必须同时存在,否则update_time在 insert 时也会被写(值同 create_time) - MySQL 5.6+ 支持
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,但 ThinkPHP 不会读取该默认值,仍需开启autoWriteTimestamp
软删除字段(delete_time)怎么一起填?
它不属于时间戳自动写入范围,也不走 before_update —— 删除操作走的是 softDelete 行为,触发 before_delete 事件。
- 启用软删除需在模型中加
use SoftDelete;并设置protected $deleteTime = 'delete_time'; - 在
beforeDelete()里手动赋值:$this->delete_time = date('Y-m-d H:i:s');(不能用$this->deleteTime,那是配置项) - 注意:
restore()不触发任何模型事件,恢复时需显式重置delete_time为null - 如果数据库字段是
datetime类型但允许为NULL,就别用0000-00-00 00:00:00做标记,ThinkPHP 软删除默认用NULL
beforeDelete() 里没填 delete_time,以及 data() 调用顺序不对导致填充失效——这两个点一出,日志里根本看不出哪里断掉的。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











