denismitr/laravel-event-recorder

Laravel 事件记录器

v2.0 2018-08-15 16:08 UTC

This package is auto-updated.

Last update: 2024-09-23 09:10:16 UTC


README

Build Status

作者

Denis Mitrofanov

要求

PHP 7.0 或更高版本,MYSQL 5.7 或更高版本,或 POSTGRES 可能任何 9.* 版本或更高版本都可以,Laravel >=5.5

版本 2.x

概述

任何需要记录到数据库的类必须实现 Denismitr\EventRecorder\Contracts\ShouldBeRecorded 接口或扩展 Denismitr\EventRecorder\ConditionallyRecordable 抽象类,该抽象类可以在某些条件下记录事件。两种方式都强制实现两个方法 getProperties(): arraygetDescription(): string,如果扩展抽象类,还可以在需要跳过某些条件下的事件记录时覆盖方法。由 getProperties() 返回的属性是您希望记录/持久化的给定事件的任意 键值对 数组(见下例)。getDescription(): string 只是事件的简单文本形式。属性以 json 格式存储,描述是 VARCHAR 512(可配置)字符串字段。

安装

使用 composer composer require denismitr/laravel-event-recorder

在 Laravel 5.5 中,服务提供程序将自动注册。但您也可以在 config/app.php 文件中手动注册

'providers' => [
    // ...
    Denismitr\EventRecorder\EventRecorderServiceProvider::class,
];

您可以使用以下命令发布迁移

php artisan vendor:publish --provider="Denismitr\EventRecorder\EventRecorderServiceProvider" --tag="migrations"

您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="Denismitr\EventRecorder\EventRecorderServiceProvider" --tag="config"

在迁移已发布并且您对配置满意后,运行迁移: php artisan migrate

使用方法

让我们假设我们有一个 MoneyAddedToWallet 事件

class MoneyAddedToWallet implements ShouldBeRecorded
{
    /**
     * @var Wallet
     */
    public $wallet;

    /**
     * @var int
     */
    public $amount;

    /**
     * MoneyAddedToWallet constructor.
     * @param Wallet $wallet
     * @param int $amount
     */
    public function __construct(Wallet $wallet, int $amount)
    {
        $this->wallet = $wallet;
        $this->amount = $amount;
    }

    public function getProperties(): array
    {
        return [
            'wallet_id' => $this->wallet->id,
            'amount' => $this->amount,
            'user_id' => $this->wallet->user_id,
            'operation' => 'credit',
        ];
    }

    public function getDescription(): string
    {
        return vsprintf("User with ID %s added %d to the wallet with ID %s", [
            $this->wallet->user_id,
            $this->amount,
            $this->wallet->id,
        ]);
    }
}

或者另一个继承选项

class MoneyAddedToWallet extends ConditionallyRecordable
{
    use TriggeredByUser;

    /**
     * @var Wallet
     */
    public $wallet;

    /**
     * @var int
     */
    public $amount;

    /**
     * @var bool
     */
    public $byAdmin;

    /**
     * MoneyAddedToWallet constructor.
     * @param Wallet $wallet
     * @param int $amount
     * @param bool $byAdmin
     */
    public function __construct(Wallet $wallet, int $amount, $byAdmin = false)
    {
        $this->wallet = $wallet;
        $this->amount = $amount;
        $this->byAdmin = $byAdmin;
    }

    public function getProperties(): array
    {
        return [
            'wallet_id' => $this->wallet->id,
            'amount' => $this->amount,
            'user_id' => $this->getTriggeredById(),
            'operation' => 'credit',
        ];
    }

    public function getDescription(): string
    {
        return vsprintf("User with ID %s added $%d to the wallet with ID %s", [
            $this->getTriggeredById(),
            $this->amount,
            $this->wallet->id,
        ]);
    }

    // This method overrides default implementation
    // that always return false
    public function shouldBeSkipped(): bool
    {
        // skip events generated by admin action
        return !! $this->byAdmin;
    }
}

在它触发后。会在 recorded_events 表中创建一条记录。以下是从测试文件中摘录的内容,希望能解释正在发生的事情。

event(new MoneyAddedToWallet($this->wallet, 1234));

$recordedEvent = RecordedEvent::first();

$this->assertEquals(MoneyAddedToWallet::class, $recordedEvent->class);
// json properties
$this->assertEquals(1234, $recordedEvent->properties->get('amount'));
$this->assertEquals($this->wallet->id, $recordedEvent->properties->get('wallet_id'));
$this->assertEquals($this->user->id, $recordedEvent->properties->get('user_id'));
$this->assertEquals('credit', $recordedEvent->properties->get('operation'));

$this->assertDatabaseHas('recorded_events', [
    'name' => 'money_added_to_wallet',
    'class' => 'Denismitr\EventRecorder\Tests\Stubs\Events\MoneyAddedToWallet',
    'description' => "User with ID {$this->user->id} added 1234 to the wallet with ID {$this->wallet->id}"
]);

有两点需要注意

  • 首先 - 此软件包使用依赖项 denismitr/laravel-json-attributes 以优雅的方式处理 JSON 属性。有关更多信息,请参阅 文档
  • 其次 - 在 recorded_events 中有一个名为 name 的列,它是通过完整的事件类名以 snake cased class name(不带命名空间)的形式生成的。

触发条件

截至版本 1.0,软件包支持记录触发事件的用户的 ID,并从版本 2.0 开始,您还可以存储用户的任意属性。如果您在要记录的事件类中使用特质 Denismitr\EventRecorder\TriggeredByUser,当事件发生时,当前登录用户的 ID 将与其他数据一起保存。在 recorded_events 中用于此的数据库列称为 triggered_by_id。在 RecordedEvents 模型中定义了 Laravel 的 belongsTo 关联。这样,您可以检索触发事件的用户的实例。

自2.0版本起,在模式中添加了一个triggered_by_properties列,并且增加了一个新的特质Denismitr\EventRecorder\Traits\CanTriggerEvents,该特质负责从用户数据中选择并过滤以存储到该列中。使用此特质是可选的。默认情况下,它将持久化给定用户模型的所有属性,除了标准Laravel用户模型中包含的$hidden数组中的那些属性。您可以通过在用户模型中添加public $eventAttributeBlacklist = [];并填充要排除的属性来进一步控制不应持久化的属性。

由于此特质仅负责将用户数据作为json存储,因此不使用它不会阻止将用户ID作为triggered_by_id存储,这完全是Denismitr\EventRecorder\TriggeredByUser和使用的活动类的责任。

配置

配置文件的内容如下

return [
    'triggered_by_id_type' => 'unsignedInteger',

    'triggered_by_class' => 'App\User',

    'max_length' => [
        'event_name' => 100,
        'event_description' => 512,
    ]
];

如果您需要更改这些属性中的某些属性,请确保在实际上运行php artisan migrate之前进行更改,否则您将不得不执行php artisan migrate:fresh,或者如果已经不可能,您将不得不手动创建更改您数据库模式逻辑。