phpgears/event-sourcing

dev-master 2020-09-16 21:21 UTC

This package is auto-updated.

Last update: 2024-09-13 06:49:24 UTC


README

PHP version Latest Version License

Build Status Style Check Code Quality Code Coverage

Total Downloads Monthly Downloads

事件源

事件源基础

安装

Composer

composer require phpgears/event-sourcing

使用

需要 composer 自动加载文件

require './vendor/autoload.php';

聚合身份

聚合身份由 gears/identity 提供,前往那里了解相关信息

聚合事件

聚合事件必须实现 Gears\EventSourcing\Event\AggregateEvent 接口,以便它们可以被聚合根使用。为了简单起见,您可以从 Gears\EventSourcing\Event\AbstractAggregateEvent 扩展

use Gears\EventSourcing\Event\AbstractAggregateEvent;
use Gears\Identity\Identity;

class AggregateCreated extends AbstractAggregateEvent
{
    public static function instantiate(Identity $aggregateId)
    {
        return self::occurred($aggregateId, []);
    }
}

/**
 * @method getThing(): string
 */
class SomethingHappened extends AbstractAggregateEvent
{
    public static function hasHappened(Identity $aggregateId, string $whatHappened)
    {
        return self::occurred($aggregateId, ['thing' => $whatHappened]);
    }
}

/**
 * @method getReason(): string
 */
class SomethingFinished extends AbstractAggregateEvent
{
    public static function hasFinished(Identity $aggregateId, string $reason)
    {
        return self::occurred($aggregateId, ['reason' => $reason]);
    }
}

请注意,AbstractAggregateEvent 构造函数是受保护的,这迫使我们创建静态命名构造函数方法,以便利用负载的类型提示。虽然您可以使用受保护的方法创建聚合事件,但您被鼓励使用 occurred 方法

然后这些事件会被记录并在聚合根上应用

聚合根

聚合根应该实现 Gears\EventSourcing\Aggregate\AggregateRoot 接口。为了简单起见,您可以从 Gears\EventSourcing\Aggregate\AbstractAggregateRoot 扩展

use Gears\EventSourcing\Aggregate\AbstractAggregateRoot;
use Gears\Identity\Identity;

class CustomAggregate extends AbstractAggregateRoot
{
    public static function create(Identity $identity): self
    {
        $instance = new self();
        
        $instance->recordAggregateEvent(AggregateCreated::instantiate($identity));
        
        return $instance;
    }

    public function doSomething(): void
    {
        $this->recordAggregateEvent(SomethingHappened::hasHappened($this->getIdentity(), 'this happened'));
    }

    public function finishSomething(): void
    {
        $this->recordAggregateEvent(SomethingFinished::hasFinished($this->getIdentity(), 'this finished'));
        $this->recordEvent(WhateverFinished::instance());
    }

    protected function applyAggregateCreated(AggregateCreated $event): void
    {
        $this->setIdentity($event->getAggregateId());
    }

    protected function applySomethingHappened(SomethingHappened $event): void
    {
        // do something with $event->getThing();
    }

    protected function applySomethingFinished(SomethingFinished $event): void
    {
        // do something with $event->getReason();
    }
}

聚合操作

聚合中的每个操作都应该通过聚合事件进行,即使是聚合的创建(如上面的示例所示),这也是为什么 AbstractAggregateRoot 构造函数是受保护的。

聚合事件代表了与事件源系统相关的事实,例如前面示例中的 AggregateCreated、SomethingHappened 和 SomethingFinished

最终应收集聚合事件,持久化到事件存储库,并根据正在运行的项目机制最终分发到事件总线

$aggregateId = CustomAggregateIdentity::fromString('4c4316cb-b48b-44fb-a034-90d789966bac');
$customAggregate = CustomAggregate::create($aggregateId);
$customAggregate->doSomething();

$eventStore->store($customAggregate->collectRecordedAggregateEvents());

聚合事件与领域事件

这是此包与其他事件源库之间的一个关键区别

聚合根可以收集两种基本不同类型的事件,上面已经讨论过的聚合事件,第二种类型的事件是领域事件,它们代表了与领域相关的事实

它们在概念上和谁对这些事件相关或意味着上有很大差异。虽然聚合事件意味着仅用于事件源系统,即事件存储持久化、聚合根重建、投影、快照、叙事和其他,领域事件与应用程序领域本身相关,即本系统以及/或其他系统部分或界限上下文

您绝对不应该使用聚合事件来驱动应用程序执行或向系统的其他部分发出信号,您必须使用领域事件来达到这些目的

领域事件应被收集并发送到事件总线,前往 gears/event 了解更多关于此主题的信息

foreach ($customAggregate->collectRecordedEvents() as $domainEvent) {
    /** @var \Gears\Event\EventBus $eventBus */
    $eventBus->dispatch($domainEvent);
}
事件粒度

在处理这两种类型的事件时,粒度至关重要。作为一般规则,您可以认为聚合事件可以映射到可以在聚合根上执行的原子操作,而领域事件可以被视为用户可以在领域上执行的操作,它们在大多数情况下将具有 1:1 的关系,但在所有情况下不一定

一个有助于理解这种差异的示例是一个两步过程,即用户在具有电子邮件验证的系统中的注册过程

虽然第一步中在系统中创建了一个用户(数据被完全或部分收集),但用户不能被认为是完全注册,直到他在第二步中验证了他的电子邮件

您可以考虑两种方法在用户聚合中完成此任务:createUser(),该方法使用提供的任何数据创建用户聚合根,以及validateUser(),该方法根据例如发送到其电子邮件的代码验证用户

这两种方法都将创建一个将最终持久化到事件存储库的聚合事件,但只有后者将创建一个UserRegistered领域事件,这可能对您的系统其他部分(例如在账单边界上下文中创建用户钱包)相关

聚合存储库

事件存储

并发

快照存储

贡献

发现了一个错误或者有功能请求?请创建一个新问题。在创建之前,请查看现有的问题。

请参阅CONTRIBUTING.md文件。

许可证

有关许可证条款的副本,请参阅源代码中包含的LICENSE文件。