laravel-用户活动以及模型变动日志-spatie/laravel-activitylog

用户活动以及模型变动日志 ——spatie/laravel-activitylog

今天要学习的扩展包是 spatie/laravel-activitylog 它为我们提供了记录用户活动日志的功能,同时还提供了记录模型日志的功能。这个扩展包的开发者你应该比较熟悉了,spatie/laravel-backupspatie/laravel-responsecachespatie/laravel-permission 都是他们这个组织开发的。

之前的课程中我们介绍的扩展包 venturecraft/revisionable 也有类似的功能,可以记录模型的变动日志,这节课我们可以对比看看今天要学习的扩展包是不是更加方便。

安装

$ composer require spatie/laravel-activitylog

file

将迁移文件发布出来。

$ php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="migrations"

file

执行 migrate 创建数据表。

$ php artisan migrate

file

看一下数据结构:

file

字段描述
id自增 ID 主键
log_name日志名称,用于归类
description日志内容
subject_idsubject 模型多态关联 id
subject_typesubject 模型多态关联 type
causer_idcauser 模型多态关联 id
causer_typecauser 模型多态关联 type
properties属性,保存为 json
created_at创建时间
updated_at修改时间

最后将配置文件发布出来:

$ php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="config"

file

使用

记录使用日志

打开 tinker 测试一下:

activity()->log('hello world');

file

如果当前有用户登录,则会记录下来登录的用户:

$user = User::find(2);
auth()->setUser($user);
activity()->log('记录登录用户的日志');

命令行中我们想模拟用户登录,可以使用 auth()->setUser

file

当然我们也可以传入参数指定相关数据:

  • inLog —— 等同于 useLog,记录日志的名称,用于分类;
  • performedOn —— 影响的模型;
  • causedBy —— 由谁引起的日志;
  • withProperties —— 其他需要记录的属性。
$topic = Topic::first();
$causedUser = User::find(3);
activity()->inLog('test')->performedOn($topic)->causedBy($causedUser)->withProperties(['data' => 'test'])->log('测试参数');

file

查看一下数据:

file

  1. 未登录用户的,只是记录了描述日志;
  2. 登录用户,记录用户,以及描述日志;
  3. 修改相关参数后的日志。

使用起来非常简单,只需要在需要记录的地方添加上面这样的代码即可。

比如我们记录一下用户的回复日志。

app/Http/Controllers/RepliesController.php

.
.
.
    public function store(ReplyRequest $request, Reply $reply)
    {
        $reply->content = $request->content;
        $reply->user_id = Auth::id();
        $reply->topic_id = $request->topic_id;
        $reply->save();

        activity('reply')->performedOn($reply)->log(':causer.name 添加了一条回复: :subject.content');

        return redirect()->to($reply->topic->link())->with('sucess', '回复创建成功!');
    }

    public function destroy(Reply $reply)
    {
        $this->authorize('destroy', $reply);
        $reply->delete();

        activity('reply')->performedOn($reply)->log(':causer.name 删除了一条回复: :subject.content');

        return redirect()->to($reply->topic->link())->with('success', '成功删除回复!');
    }
.
.
.

在记录日志的时候,也就是 log 方法的参数中可以使用变量,这些变量会被替换:

  • :subject —— 表示 performedOn 的模型,可以使用点( :subject.column )表示模型属性
  • :causer —— 表示 causedBy 的模型,可以使用点( :causer.column )表示模型属性
  • :properties —— 表示 withProperties 自定义的属性,可以使用点( :properties.column )表示对应的模型。

添加一个回复:

file

删除这个回复:

file

查看数据库日志:

file

查询相关日志

扩展包使用的日志模型在这里 ——Spatie\Activitylog\Models\Activity

所以我们可以直接通过这个模型做一些查询。打开 tinker:

查询对应名称的日志,比如我们查询所有回复相关的日志。

use Spatie\Activitylog\Models\Activity
Activity::inLog('reply')->get();

file

查询 id 为 2 的用户相关的日志:

$user = User::find(2);
Activity::causedBy($user)->get();

file

还可以进一步过滤

Activity::causedBy($user)->inLog('default')->get();

file

查询某个回复相关的日志:

$topic = Topic::find(1);
Activity::forSubject($topic)->get();

file

我们可以灵活的利用扩展包的模型,进行查询,总结一下:

  • inLog —— 查询日志名称;
  • forSubject —— 查询 subject;
  • causedBy—— 查询 causer。

还可以通过模型方便的获取属性。

$activity = Activity::forSubject($topic)->first();
$activity->causer;
$activity->subject;
$activity->getExtraProperty('data');

getExtraProperty 方法可以获取 Properties 中的值。

file

记录模型变化

默认情况下扩展包会通过模型的 createdupdateddeleted 事件,记录模型变化,测试一下。

首先需要给需要记录的模型增加一个 Trait

app/Models/Topic.php

.
.
.
use Spatie\Activitylog\Traits\LogsActivity;

class Topic extends Model
{
    use LogsActivity;
.
.
.

创建一个话题,修改属性,然后删除,查看数据库:

file

创建,修改,删除都会触发日志的记录,但是默认情况下 description 只记录了模型的事件名,而且修改日志没有记录模型属性的前后变化,我们需要继续修改一下。

app/Models/Topic.php

.
.
.
    protected static $ignoreChangedAttributes = ['updated_at'];
    protected static $logAttributes = ['title', 'category_id'];
    protected static $logOnlyDirty = true;

    public function getDescriptionForEvent(string $eventName): string
    {
        switch ($eventName) {
            case 'created':
                $description = '话题被创建';
                break;
            case 'updated':
                $description = '话题被修改';
                break;
            case 'deleted':
                $description = '话题被删除';
                break;
            default:
                $description = $eventName;
                break;
        }
        return $description;
    }
.
.
.

重新添加并修改一个话题,查看数据库:

file

description 被修改我们定义的样子,properties 中记录了模型的属性,打开 tinker 测试一下,修改了代码记得重启 tinker:

$topic = Topic::find(103);
$topic->activity

由于我们给 Topic 模型增加了 Trait,所以可以直接通过 activity 关系获取模型相关的所有日志。

file

由于我们记录了 title 以及 category_id 的变化,所以通过 activity 的 changes 方法就可以获取所有的模型的变化情况。

file

attributes 是模型当前的属性日志,old 是变化之前的属性日志。

扩展包并没有提供根据单个模型清理日志的功能,提供了一个命令 activitylog:clean 用来清除config('activitylog.delete_records_older_than_days) 之前的日志,我们可以根据需要调整配置,并且增加一个计划任务。

代码版本控制

$ git add -A
$ git commit -m 'spatie/laravel-activitylog'
tags: laravel,activitylog