denismitr/laravel-event-recorder 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

denismitr/laravel-event-recorder

Composer 安装命令:

composer require denismitr/laravel-event-recorder

包简介

Laravel Event Recorder

README 文档

README

Build Status

Author

Denis Mitrofanov

Requirements

PHP 7.0 or higher MYSQL 5.7 or higher or POSTGRES probably any 9.* version or higher will do Laravel >=5.5

Version 2.x

Overview

Any class that should be recorded to DB must implement the Denismitr\EventRecorder\Contracts\ShouldBeRecorded interface or extend Denismitr\EventRecorder\ConditionallyRecordable abstract class that gives ability to record events only under certain conditions. Both ways enforce the concrete implementation of two methods getProperties(): array and getDescription(): string methods, plus a method public function shouldBeSkipped(): bool, in case of extending the abstract class, can be overridden when you wish to skip the recording of event under certain conditions. Properties returned by the getProperties() are an arbitrary array of important key-value pairs for the given event that you wish to log/persist. (see example below). getDescription(): string is just a human readable form of the event that occurred. The properties are stored in json format and description is a VARCHAR 512 (configurable) string field.

Installation

Via composer composer require denismitr/laravel-event-recorder

In Laravel 5.5 the service provider will automatically get registered. But you can register it manually too in the config/app.php file:

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

You can publish the migration with:

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

You can publish the config file with:

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

After the migration has been published and you are happy with configuration, run the mirations: php artisan migrate

Usage

Let's imagine we have a MoneyAddedToWallet event:

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,
        ]);
    }
}

Or another option with inheritance:

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;
    }
}

After it is fired. A record in the recorded_events table will be created. The following extract from test file hopefully explains what is going on.

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}"
]);

Two important things to notice:

  • first - this package uses a dependency denismitr/laravel-json-attributes to handle json properties in an elegant way. See the docs for more information.
  • second - there is a column name in recorded_events it is being generated from the full event class in the form of snake cased class name (without the namespace).

Triggered By

As of version 1.0 package supports recording an ID of a user who triggered an event and as of version 2.0 also you can store arbitrary attributes of the user. If you use a trait Denismitr\EventRecorder\TriggeredByUser in the event class you wish to record, when event occurs the user who is currently logged in ID will be saved along with other data for this event. The DB column in recorded_events used for this is called triggered_by_id. There is a Laravel belongsTo relationship defined in RecordedEvents model. This way you can retrieve an instance of a user whose actions have triggered the event.

As of version 2.0 there is a nullable triggered_by_properties column added to the schema. And a new trait Denismitr\EventRecorder\Traits\CanTriggerEvents that is responsible for picking, filtering the user data for stroing into that column. Use of this trait is optional. By default it will persist all attributes that the given User model has, except for those included in the standard Laravel User model $hidden array. You can further control what attributes should not be persisted by adding public $eventAttributeBlacklist = []; to your User model and filling it with attributes you wish to exclude.

Since this trait is responsible only for storing user data as json, not using it will not prevent the storing of user id as triggered_by_id that is fully the responsibility of the Denismitr\EventRecorder\TriggeredByUser and the event class where it is being used.

Configuration

The contents of configuration file is as follows:

return [
    'triggered_by_id_type' => 'unsignedInteger',

    'triggered_by_class' => 'App\User',

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

If you need to change some of these properties, be sure to do that before you actually run the php artisan migrate, otherwise you will have to do either php artisan migrate:fresh or if it is already impossible, you would have to manually create the logic for changing your DB schema.

denismitr/laravel-event-recorder 适用场景与选型建议

denismitr/laravel-event-recorder 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 90 次下载、GitHub Stars 达 4, 最近一次更新时间为 2018 年 08 月 08 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「events」 「laravel」 「event-sourcing」 「denismitr」 「event-recording」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 denismitr/laravel-event-recorder 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 denismitr/laravel-event-recorder 我们能提供哪些服务?
定制开发 / 二次开发

基于 denismitr/laravel-event-recorder 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 90
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 4
  • 点击次数: 11
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 4
  • Watchers: 2
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-08-08