digitalrisks/laravel-eventstore 问题修复 & 功能扩展

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

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

digitalrisks/laravel-eventstore

Composer 安装命令:

composer require digitalrisks/laravel-eventstore

包简介

All things regarding integrating Greg Young's Event Store into Laravel

README 文档

README

This package integrates Greg Young's eventstore into Laravel's event system. By simply implementing ShouldBeStored on your events, they will be sent to eventstore. In the same fashion you can also setup listeners that can respond to events that are received from the eventstore.

Example implementation: https://github.com/digitalrisks/laravel-eventstore-example

Installation

You can install the package via composer:

composer require digitalrisks/laravel-eventstore

Add the base service provider for the package.

<?php

namespace App\Providers;

use Illuminate\Support\Str;
use DigitalRisks\LaravelEventStore\EventStore;
use DigitalRisks\LaravelEventStore\ServiceProvider as EventStoreApplicationServiceProvider;

class EventStoreServiceProvider extends EventStoreApplicationServiceProvider
{
    /**
     * Bootstrap the application services.
     */
    public function boot()
    {
        parent::boot();
    }

    /**
     * Set the eventToClass method.
     *
     * @return void
     */
    public function eventClasses()
    {
        // This will set your events to be the following '\\App\Events\\' . $event->getType();.
        EventStore::eventToClass();

        // You can customise this by doing the following.
        EventStore::eventToClass(function ($event) {
            return 'App\Events\\' . Str::studly($event->getType());
        });
    }

    /**
     * Handle logging when event is triggered.
     *
     * @return void
     */
    public function logger()
    {
        // This will setup the logger for when an event happens.
        EventStore::logger();

        // You can customise this by doing the following.
        EventStore::logger(function ($event, $type) {
            Log::info($event->getType());
        });
    }

    /**
     * Register the application services.
     */
    public function register()
    {
        parent::register();
    }
}

In your config/app.php file, add the following to the providers array.

    /*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    |
    | The service providers listed here will be automatically loaded on the
    | request to your application. Feel free to add your own services to
    | this array to grant expanded functionality to your applications.
    |
    */

    'providers' => [
        ...
        App\Providers\EventStoreServiceProvider::class,
    ],

Example Event

use DigitalRisks\LaravelEventStore\Contracts\CouldBeReceived;
use DigitalRisks\LaravelEventStore\Contracts\ShouldBeStored;
use DigitalRisks\LaravelEventStore\Traits\ReceivedFromEventStore;
use DigitalRisks\LaravelEventStore\Traits\SendsToEventStore;

class QuoteStarted implements ShouldBeStored, CouldBeReceived
{
    use SendsToEventStore, ReceivedFromEventStore;

    public $email;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($email = null)
    {
        $this->email = $email;
    }
}

Usage - Sending Events

The package will automatically send events dispatched in Laravel that implement the ShouldBeStored interface.

interface ShouldBeStored
{
    public function getEventStream(): string;

    public function getEventType(): string;

    public function getEventId(): string;

    public function getData(): array;

    public function getMetadata(): array;
}

To assist in implementing the interface, the package comes with a SendsToEventStore trait which meets the requirements of the interface in a basic fashion:

  • Event Type: the event's class name
  • Event ID: A UUID v4 will be generated
  • Data: all of the events public properties are automatically serialized
  • Metadata: data from all of the methods marked with @metadata will be collected and serialized
use DigitalRisks\LaravelEventStore\Contracts\CouldBeReceived;
use DigitalRisks\LaravelEventStore\Contracts\ShouldBeStored;
use DigitalRisks\LaravelEventStore\Traits\SendsToEventStore;

class AccountCreated implements ShouldBeStored, CouldBeReceived
{
    use SendsToEventStore;
    
    public function getEventStream(): string
    {
        return 'accounts';
    }
}

Then raising an event is done in the normal Laravel way:

event(new AccountCreated('foo@bar.com'));

Metadata

Metadata can help trace events around your system. You can include any of the following traits on your event to attach metadata automatically

  • AddsHerokuMetadata
  • AddsLaravelMetadata
  • AddsUserMetaData

Or you can define your own methods to collect metadata. Any method with the @metadata annotation will be called:

class AccountCreated implements ShouldBeStored
{
    use DigitalRisks\LaravelEventStore\Traits\AddsLaravelMetadata;
    
    /** @metadata */
    public function collectIpMetadata()
    {
        return [
            'ip' => $_SERVER['REMOTE_ADDR'],
        ];
    }
}

Testing

If you would like to test that your events are being fired correctly, you can use the Laravel Event::mock method, or the package comes with helpers that interact with an eventstore to confirm they have been stored correctly.

class AccountCreatedTest extends TestCase
{
    use DigitalRisks\LaravelEventStore\Tests\Traits\InteractsWithEventStore;

    public function test_it_creates_an_event_when_an_account_is_created()
    {
        // Act.
        $this->json('POST', '/api/accounts', ['email' => 'foo@bar.com']);

        // Assert.
        $this->assertEventStoreEventRaised('AccountCreated', 'accounts', ['email' => 'foo@bar.com']);
    }
}

Usage - Receiving Events

You must first run the worker which will listen for events.

None of the options are required. By default it will run the persistance subscription with a timeout of 10 seconds and 1 parallel event at a time.

$ php artisan eventstore:worker {--parallel= : How many events to run in parallel.} {--timeout= : How long the event should time out for.}

$ php artisan eventstore:worker --parallel=10 --timeout=5

When an event is received, it will be mapped to the Laravel event and the original EventRecord can be accessed via getEventRecord().

You can react to these events in the normal Laravel fashion.

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        AccountCreated::class => [SendAccountCreatedEmail::class],
    ];
}
class SendAccountCreatedEmail
{
    public function handle(AccountCreated $event)
    {
        Mail::to($event->email)->send('Here is your account');
    }
}

If you are listening to the same stream where you are firing events, your events WILL BE fired twice - once by Laravel and once received from the event store. You may choose react synchronously if $event->getEventRecord() is false and asynchronously if $event->getEventRecord() returns the eventstore record.

class SendAccountCreatedEmail
{
    public function handle(AccountCreated $event)
    {
        // Side effect, let's only send an email when we've triggered this event and not when replaying events
        if (! $event->getEventRecord()) return;

        Mail::to($event->email)->send('Here is your account');
    }
}

class SaveAccountToDatabase
{
    public function handle(AccountCreated $event)
    {
        // State change, let's ensure we update our database with this event.
        if ($event->getEventRecord()) return;

        Account::create(['email' => $event->email]);
    }
}

In addition, if you would like to test that are events are created AND how the application reacts to those events you may set eventstore.connection to sync. This will trick the event listeners into thinking that the event has been received from the eventstore.

Testing

If you would like to test your listeners, the package comes with several helper methods to mimic events being received from the worker.

class QuoteStartedTest extends TestCase
{
    use \DigitalRisks\LaravelEventStore\Tests\MakesEventRecords;

    public function test_it_sends_an_email_when_an_account_is_created()
    {
        // Arrange.
        $event = $this->makeEventRecord('AccountCreated', ['email' => 'foo@bar.com');

        // Act.
        event($event->getType(), $event);

        // Assert.
        Mail::assertSentTo('foo@bar.com');
    }
}

In addition you may set set eventstore.connection to sync, which will trick your listeners

Usage - Replaying Events

You can replay events by using the replay command

php artisan eventstore:replay <stream> <event>

<event> can be a single event number or a range like 390-396

Configuration

The defaults are set in config/eventstore.php. Copy this file to your own config directory to modify the values:

php artisan vendor:publish --provider="DigitalRisks\LaravelEventStore\ServiceProvider"
return [
    'tcp_url' => 'tls://admin:changeit@localhost:1113',
    'http_url' => 'http://admin:changeit@localhost:2113',
    'group' => 'account-email-subscription',
    'volatile_streams' => ['quotes', 'accounts'],
    'subscription_streams' => ['quotes', 'accounts'],
];

Testing

composer test

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email pawel.trauth@digitalrisks.co.uk instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

digitalrisks/laravel-eventstore 适用场景与选型建议

digitalrisks/laravel-eventstore 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 55.32k 次下载、GitHub Stars 达 16, 最近一次更新时间为 2019 年 06 月 18 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

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

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

与 digitalrisks/laravel-eventstore 相关的其它包

同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:

统计信息

  • 总下载量: 55.32k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 16
  • 点击次数: 5
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 16
  • Watchers: 5
  • Forks: 4
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2019-06-18