Laravel如何实现行内单元格变更记录?突破updated_at局限
嘿,这个问题我之前做Laravel项目的时候刚好碰到过!确实,Laravel自带的updated_at字段只能帮我们追踪更新时间,但要搞清楚具体哪些字段被修改了,其实有几个实用的方案,我给你梳理一下:
方案一:用Eloquent原生方法手动对比
Laravel的模型自带getOriginal()方法,可以获取到模型更新前的原始属性值,我们可以在模型的updated事件里对比原始值和更新后的值,找出差异:
protected static function booted() { static::updated(function ($model) { // 获取更新前的原始数据 $originalValues = $model->getOriginal(); // 获取更新后的当前数据 $currentValues = $model->getAttributes(); // 筛选出真正有变化的字段(排除自动维护的时间字段) $changedFields = []; foreach ($currentValues as $field => $value) { if (!in_array($field, ['created_at', 'updated_at']) && $originalValues[$field] !== $value) { $changedFields[$field] = [ 'old_value' => $originalValues[$field], 'new_value' => $value ]; } } // 如果有变化,就把差异存入日志表 if (!empty($changedFields)) { // 这里假设你已经创建了ActivityLog模型和对应的表 \App\Models\ActivityLog::create([ 'model_type' => get_class($model), 'model_id' => $model->id, 'changes' => json_encode($changedFields), 'operated_at' => now(), 'operator_id' => auth()->id() // 还能记录操作人ID ]); } }); }
这个方案完全依赖Laravel原生功能,不需要额外安装包,适合轻量需求的场景。
方案二:用成熟的第三方包快速实现
如果不想自己写重复逻辑,社区有非常好用的现成包,比如spatie/laravel-activitylog,它能自动帮你追踪模型的增删改操作,还能精准记录字段的新旧变化:
- 先安装包:
composer require spatie/laravel-activitylog
- 发布迁移文件和配置文件:
php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider"
- 运行迁移创建日志表:
php artisan migrate
- 在需要追踪的模型里引入
trait并配置:
use Spatie\Activitylog\Traits\LogsActivity; class Post extends Model { use LogsActivity; // 配置要追踪的字段(如果用$logFillable则追踪所有fillable字段) protected $logAttributes = ['title', 'content', 'status']; // 自定义日志的描述文本 public function getDescriptionForEvent(string $eventName): string { return "文章已被{$eventName}"; } }
之后每次模型更新,这个包就会自动把字段的变化记录到activity_log表中,你可以直接通过模型关联或者包提供的方法查询历史记录,非常省心。
方案三:自定义观察者实现复杂逻辑
如果你的项目有特殊的日志规则(比如不同模型需要不同的追踪逻辑),可以用Laravel的观察者模式来实现:
- 生成对应模型的观察者:
php artisan make:observer PostObserver --model=Post
- 在观察者的
updated方法里实现差异对比和日志记录:
namespace App\Observers; use App\Models\Post; use App\Models\ActivityLog; class PostObserver { public function updated(Post $post) { $original = $post->getOriginal(); $current = $post->getAttributes(); // 只追踪我们关心的字段,并且过滤掉没有变化的内容 $changes = array_filter($current, function ($value, $key) use ($original) { return in_array($key, ['title', 'content']) && $original[$key] !== $value; }, ARRAY_FILTER_USE_BOTH); if (!empty($changes)) { ActivityLog::create([ 'model' => 'Post', 'model_id' => $post->id, 'changes' => json_encode($changes), 'operator_id' => auth()->id() ]); } } }
- 在
AppServiceProvider的boot方法里注册观察者:
public function boot() { Post::observe(PostObserver::class); }
这种方式灵活性最高,适合需要定制化日志规则的场景。
需要注意的是,对于JSON字段或者关联模型的变化,上面的基础逻辑可能需要额外处理,但已经能覆盖大部分常规的字段追踪需求啦!
内容的提问来源于stack exchange,提问作者Tanmay
相关产品推荐
相关产品推荐

