digitalrisks / lese
Laravel事件源Eventstore桥接层
Requires
- php-http/guzzle6-adapter: ^2.0
- prooph/event-store-client: ^1.0@RC
- prooph/event-store-http-client: ^1.0@beta
- spatie/laravel-event-sourcing: ^3.1
Requires (Dev)
- morrislaptop/var-dumper-with-context: ^0.3.2
- orchestra/testbench: ^5.2
- phpunit/phpunit: ^9.1
This package is auto-updated.
Last update: 2024-09-21 20:28:17 UTC
README
或者德语中的“read”(读取),这在某种程度上适用于事件源。它几乎是一个好名字。
此包用Laravel事件源和EventStore替换了事件和快照存储模型。EventStore在数据库之上具有一些优势,因为它是为事件源专门构建的。
该包还包括一个订阅命令,以便您可以监听系统其他服务中起源的事件。
安装
首先,让我们将包和Laravel事件源引入我们的Laravel应用程序。
composer require digitalrisks/lese
然后发布Laravel事件源和Lese配置文件。
php artisan vendor:publish --provider="Spatie\EventSourcing\EventSourcingServiceProvider" --tag="config" php artisan vendor:publish --provider="DigitalRisks\Lese\LeseServiceProvider" --tag="config"
然后进入config/event-sourcing.php
以将EventStore配置为我们的事件和快照存储仓库。
/* * This class is responsible for storing events. To add extra behaviour you * can change this to a class of your own. The only restriction is that * it should implement \Spatie\EventSourcing\StoredEventRepository. */ 'stored_event_repository' => \DigitalRisks\Lese\EventStoreStoredEventRepository::class, /* * This class is responsible for storing snapshots. To add extra behaviour you * can change this to a class of your own. The only restriction is that * it should implement \Spatie\EventSourcing\StoredEventRepository. */ 'snapshot_repository' => \DigitalRisks\Lese\EventStoreSnapshotRepository::class,
配置
这是在config/lese.php
中发布的配置文件的默认内容
<?php return [ /** * The EventStore connection to use when subscribing to events from external * services. Works with TCP or TLS connections. */ 'tcp_url' => env('EVENTSTORE_TCP_URL', 'tcp://admin:changeit@localhost:1113'), /** * The EventStore connection to use when publishing and reconstituting * aggregates. Supports HTTP or HTTPS. */ 'http_url' => env('EVENTSTORE_HTTP_URL', 'http://admin:changeit@localhost:2113'), /** * Listen to these streams when running `event-sourcing:subscribe`. Uses * a comma delimetered list from the environment as default. */ 'subscription_streams' => array_filter(explode(',', env('EVENTSTORE_SUBSCRIPTION_STREAMS'))), /** * Used as the group when connecting to an EventStore persisten subscription. */ 'group' => env('EVENTSTORE_SUBSCRIPTION_GROUP', env('APP_NAME', 'laravel')), /** * By default Aggregate classes are mapped to a category name based on their * class name. Example App\Aggregates\AccountAggregate would be published * to an account-uuid stream. This allows you to implicitly map classes * to categories so that it could be published to account_v2-uuid. */ 'aggregate_category_map' => [], /** * If not using aggregates, events need to mapped to streams to be * published. An example would be the AccoutCreated event * could be published on to the accounts stream. */ 'event_stream_map' => [], /** * If the event is not mapped to a stream, * publish to this stream by default. */ 'default_stream' => env('EVENTSTORE_DEFAULT_STREAM', 'events'), /** * The stream to listen to when replaying all events. Instead of using * $all, it is recommended to setup a project which emits events * from various streams into a stream specific for your app. */ 'all' => env('EVENTSTORE_ALL', '$all'), /** * Number of events to read in a single API * call when reconstituting events. */ 'read_size' => env('EVENTSTORE_READ_SIZE', 4096), /** * Number of events to read in a single TCP * message when replaying all events. */ 'batch_size' => env('EVENTSTORE_BATCH_SIZE', 4096), /** * This class contains a few callbacks to govern the bridge between EventStore and the * Laravel Event Sourcing package. You can customise the class to include your * own business logic. It should extend DigitalRisks\Lese\Lese */ 'lese_class' => env('EVENTSTORE_LESE_CLASS', DigitalRisks\Lese\Lese::class), ];
入门
我建议通过阅读https://docs.spatie.be/laravel-event-sourcing/v3/introduction/上的优秀指南来熟悉事件源。
下一步是获取EventStore的本地版本(您不需要数据库)。每个平台的说明都可以在https://eventstore.com/docs/getting-started/index.html找到
现在让我们创建一个简单的事件
<?php namespace App\Events; use Spatie\EventSourcing\ShouldBeStored; class MoneyAdded implements ShouldBeStored { /** @var string */ public $accountUuid; /** @var int */ public $amount; public function __construct(string $accountUuid, int $amount) { $this->accountUuid = $accountUuid; $this->amount = $amount; } }
并发送它
<?php event(new MoneyAdded('21410-81231', 100))
现在让我们创建一个简单的投影,将账户信息放入数据库。
<?php namespace App\Projectors; use App\Account; use App\Events\AccountCreated; use App\Events\AccountDeleted; use App\Events\MoneyAdded; use App\Events\MoneySubtracted; use Spatie\EventSourcing\Projectors\Projector; use Spatie\EventSourcing\Projectors\ProjectsEvents; class AccountsProjector implements Projector { use ProjectsEvents; public function onMoneyAdded(MoneyAdded $event) { $account = Account::uuid($event->accountUuid); $account->balance += $event->amount; $account->save(); } }
并将事件发送给FBI处理大额交易
<?php namespace App\Reactors; use App\Account; use App\Events\MoneyAdded; use App\Mail\BigAmountAddedMail; use Illuminate\Support\Facades\Mail; use Spatie\EventSourcing\EventHandlers\EventHandler; use Spatie\EventSourcing\EventHandlers\HandlesEvents; class BigAmountAddedReactor implements EventHandler { use HandlesEvents; public function onMoneyAdded(MoneyAdded $event) { if ($event->amount < 5000) { return; } $account = Account::uuid($event->accountUuid); Mail::to('director@fbi.gov')->send(new BigAmountAddedMail($account, $event->amount)); } }
如果以后业务想要在模型上添加number_of_deposits
属性,我们更新投影器
<?php namespace App\Projectors; use App\Account; use App\Events\AccountCreated; use App\Events\AccountDeleted; use App\Events\MoneyAdded; use App\Events\MoneySubtracted; use Spatie\EventSourcing\Projectors\Projector; use Spatie\EventSourcing\Projectors\ProjectsEvents; class AccountsProjector implements Projector { use ProjectsEvents; public function onMoneyAdded(MoneyAdded $event) { $account = Account::uuid($event->accountUuid); $account->balance += $event->amount; $account->number_of_deposits += 1; $account->save(); } }
并重新运行事件
php artisan event-sourcing:replay App\\Projectors\\AccountsProjector
通过遵循https://docs.spatie.be/laravel-event-sourcing/v3/introduction/上的指南来了解更多关于如何使用事件源的信息
聚合
如果您不使用聚合,可以跳过此部分。
为了使EventStore仓库能够获取与聚合相关的事件和/或快照,它需要了解聚合。为此,我们只需简单地覆盖以下两个方法以启动仓库并传入聚合。
protected function getStoredEventRepository(): StoredEventRepository { return resolve(EventStoreStoredEventRepository::class, ['aggregate' => $this]); } protected function getSnapshotRepository(): SnapshotRepository { return resolve(EventStoreSnapshotRepository::class, ['aggregate' => $this]); }
订阅流
该包还包括一个长时间运行的过程,类似于Pub / Sub,通过php artisan redis:subscribe
,您可以监听来自流的事件。
假设这是accounts-service
,但我们想监听来自quotes-service
的事件。当报价被转换时,我们希望为其创建一个账户。
小心:如果您监听您发布的事件,投影器和反应器将在您的应用程序中处理它们一次,并在它们再次流回时再次处理。建议您仅订阅您不发布的事件流。
在config/lese.php
中,我们将添加报价转换事件的流
/** * Listen to these streams when running `event-sourcing:subscribe`. Uses * a comma delimetered list from the environment as default. */ 'subscription_streams' => ['$et-Events\Quotes\QuoteConverted'],
然后我们可以运行以下命令在EventStore上创建持久订阅
php artisan event-sourcing:reset
小心:在重置持久订阅时,它将从第一个事件重新开始。如果您有reactors,您应该在eventstore管理员中设置
从何处开始
的值,以您希望开始的事件编号。
最后开始订阅过程
php artisan event-sourcing:subscribe
事件元数据
元数据可以帮助跟踪您系统中的事件。您可以在事件中包含以下任何属性来自动附加元数据
添加Heroku元数据
添加Laravel元数据
添加用户元数据
或者,您可以定义自己的方法来收集元数据。任何带有@metadata
注解的方法都将被调用
<?php namespace App\Events; use DigitalRisks\Lese\MetaData\HasMetaData; use DigitalRisks\Lese\MetaData\CollectsMetaData; use DigitalRisks\Lese\MetaData\AddsHerokuMetadata; use DigitalRisks\Lese\MetaData\AddsLaravelMetadata; use DigitalRisks\Lese\MetaData\AddsUserMetaData; use Spatie\EventSourcing\ShouldBeStored; class MoneyAdded implements ShouldBeStored, HasMetaData { use CollectsMetaData, AddsUserMetaData, AddsHerokuMetadata, AddsLaravelMetadata; /** @var string */ public $accountUuid; /** @var int */ public $amount; public function __construct(string $accountUuid, int $amount) { $this->accountUuid = $accountUuid; $this->amount = $amount; } /** @metadata */ public function collectIpMetadata() { return [ 'ip' => $_SERVER['REMOTE_ADDR'], ]; } }
更新日志
请参阅更新日志了解最近更改了哪些信息。
贡献
请参阅贡献指南了解详细信息。
安全
如果您发现任何与安全相关的问题,请通过电子邮件craig.morris@digitalrisks.co.uk联系,而不是使用问题跟踪器。
致谢
许可证
MIT许可证(MIT)。请参阅许可证文件以获取更多信息。