mannum/laravel-eventstore

该包已被弃用,不再维护。作者建议使用 digitalrisks/laravel-eventstore 包。

关于将 Greg Young 的 Event Store 集成到 Laravel 的所有内容

v8.4.0 2021-05-12 16:48 UTC

README

该包将 Greg Young 的 eventstore 集成到 Laravel 的事件系统中。通过简单地在您的事件上实现 ShouldBeStored 接口,它们将被发送到 eventstore。同样地,您也可以设置监听器以响应从 eventstore 接收到的事件。

示例实现: https://github.com/digitalrisks/laravel-eventstore-example

安装

您可以通过 composer 安装此包。

composer require digitalrisks/laravel-eventstore

添加包的基本服务提供者。

<?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();
    }
}

在您的 config/app.php 文件中,将以下内容添加到 providers 数组中。

    /*
    |--------------------------------------------------------------------------
    | 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,
    ],

示例事件

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

使用 - 发送事件

该包将自动发送实现了 ShouldBeStored 接口的所有在 Laravel 中派发的事件。

interface ShouldBeStored
{
    public function getEventStream(): string;

    public function getEventType(): string;

    public function getEventId(): string;

    public function getData(): array;

    public function getMetadata(): array;
}

为了帮助实现接口,该包提供了一个 SendsToEventStore 特性,它以基本的方式满足接口的要求。

  • 事件类型:事件类的名称
  • 事件 ID:将生成一个 UUID v4
  • 数据:自动序列化事件的所有公共属性
  • 元数据:收集并序列化所有标记有 @metadata 的方法中的数据
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';
    }
}

然后以正常的 Laravel 方式触发事件

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

元数据

元数据可以帮助追踪系统中的事件。您可以在事件上包含以下任何特性来自动附加元数据

  • AddsHerokuMetadata
  • AddsLaravelMetadata
  • AddsUserMetaData

或者,您可以定义自己的方法来收集元数据。任何带有 @metadata 注解的方法都将被调用

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

测试

如果您想测试事件是否正确触发,可以使用 Laravel 的 Event::mock 方法,或者该包提供与 eventstore 交互的辅助工具来确认它们是否已正确存储。

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

使用 - 接收事件

您必须首先运行工作进程,该进程将监听事件。

不需要任何选项。默认情况下,它将以 10 秒的超时时间和每次处理一个事件的方式运行持久订阅。

$ 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

当收到事件时,它将被映射到 Laravel 事件,并通过 getEventRecord() 访问原始的 EventRecord

您可以用正常的 Laravel 方式对这些事件做出反应。

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

如果您正在监听您触发事件的同一流,您的事件将被触发两次 - 一次由Laravel触发,一次从事件存储接收。如果$event->getEventRecord()为false,您可以同步响应,如果$event->getEventRecord()返回事件存储记录,则可以异步响应。

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

此外,如果您想测试事件是否已创建以及应用程序如何响应这些事件,可以将eventstore.connection设置为sync。这将使事件监听器认为事件已从事件存储接收。

测试

如果您想测试您的监听器,该软件包包含一些辅助方法来模拟从工作进程接收事件。

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

此外,您可以将eventstore.connection设置为sync,这将欺骗您的监听器。

用法 - 重放事件

您可以使用重放命令来重放事件

php artisan eventstore:replay <stream> <event>

<event>可以是单个事件编号或范围,如390-396

配置

默认设置在config/eventstore.php中设置。将此文件复制到您的配置目录以修改值

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'],
];

测试

composer test

变更日志

请参阅CHANGELOG以获取有关最近更改的更多信息。

贡献

请参阅CONTRIBUTING以获取详细信息。

安全

如果您发现任何安全相关的问题,请通过电子邮件pawel.trauth@digitalrisks.co.uk联系,而不是使用问题跟踪器。

鸣谢

许可证

MIT许可证(MIT)。请参阅许可证文件以获取更多信息。