mannum / laravel-eventstore
关于将 Greg Young 的 Event Store 集成到 Laravel 的所有内容
Requires
- php: ^7.1
- guzzlehttp/guzzle: ^6.3 || ^7.0
- illuminate/support: 5.7.* || 5.8.* || ^6.0 || ^7.0 || ^8.0
- ramsey/uuid: ^3.8 || ^4.0
- rxnet/eventstore-client: dev-ramsey-uuid-4
Requires (Dev)
- orchestra/testbench: ^5.1 || ^6.9
- phpunit/phpunit: ^8.0
- timacdonald/log-fake: ^1.4
This package is auto-updated.
Last update: 2022-02-01 13:16:50 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'));
元数据
元数据可以帮助追踪系统中的事件。您可以在事件上包含以下任何特性来自动附加元数据
AddsHerokuMetadataAddsLaravelMetadataAddsUserMetaData
或者,您可以定义自己的方法来收集元数据。任何带有 @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)。请参阅许可证文件以获取更多信息。