如何在Laravel模型中使用Spatie Laravel-activitylog记录关联信息?
在Laravel模型中使用Spatie Laravel-activitylog记录完整日志的解决方案
我来帮你搞定这个问题!其实在模型层面实现Spatie活动日志记录,同时确保subject和causer的ID、类型正确存储,有两种非常实用的方式,完全符合Laravel的开发习惯:
方法一:使用模型观察者(推荐)
模型观察者是处理模型事件最清晰的方式,适合需要记录多个事件(创建、编辑、删除等)的场景:
- 生成观察者类
运行Artisan命令创建对应模型的观察者:
php artisan make:observer ContentObserver --model=Content
(把Content换成你的实际模型名)
- 在观察者中编写日志逻辑
打开生成的app/Observers/ContentObserver.php,添加事件处理方法,这里以updated事件为例:
namespace App\Observers; use App\Models\Content; use Spatie\Activitylog\Facades\Activity; class ContentObserver { public function updated(Content $content) { // 先获取当前登录用户,避免无用户场景报错 $currentUser = auth()->user(); if ($currentUser) { Activity::causedBy($currentUser) ->performedOn($content) ->log('edited'); // 可选:添加自定义属性到日志中 // ->withProperties([ // 'old_title' => $content->getOriginal('title'), // 'new_title' => $content->title // ]); } } // 可以按需添加created、deleted、restored等事件的处理逻辑 public function created(Content $content) { $currentUser = auth()->user(); if ($currentUser) { Activity::causedBy($currentUser) ->performedOn($content) ->log('created'); } } }
- 注册观察者
在app/Providers/AppServiceProvider.php的boot方法中注册观察者:
use App\Models\Content; use App\Observers\ContentObserver; public function boot() { Content::observe(ContentObserver::class); }
方法二:直接在模型的boot方法中绑定事件
如果你的需求比较简单,不想单独创建观察者文件,可以直接在模型内部处理:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Spatie\Activitylog\Facades\Activity; class Content extends Model { protected static function boot() { parent::boot(); // 监听更新事件 static::updated(function ($content) { $currentUser = auth()->user(); if ($currentUser) { Activity::causedBy($currentUser) ->performedOn($content) ->log('edited'); } }); // 可添加其他事件 static::created(function ($content) { $currentUser = auth()->user(); if ($currentUser) { Activity::causedBy($currentUser) ->performedOn($content) ->log('created'); } }); } }
关键注意事项
- 确保获取到当前用户:模型中默认没有用户上下文,所以必须用
auth()->user()获取当前登录用户,同时要判断用户是否存在(比如命令行执行、队列任务中没有HTTP会话,用户会为null),避免报错。 - 必须明确指定
causedBy和performedOn:这两个方法是填充causer_id、causer_type以及subject_id、subject_type的关键,缺一不可。 - 非HTTP场景的处理:如果需要在命令行或队列中记录日志,可以提前设置一个“系统用户”作为默认causer,比如:
// 当auth()->user()为null时使用系统用户 $causer = auth()->user() ?? User::find(1); // 假设ID为1的是系统用户 Activity::causedBy($causer)->performedOn($content)->log('edited');
内容的提问来源于stack exchange,提问作者Vijay Rana
相关产品推荐
相关产品推荐

