php linajieshujuku,PHP的CQRS + Event Sourcing库包:dudulina

PHP号称是最好的服务器端编程语言,CQRS + Event Sourcing已经在PHP社区和.NET社区蔓延开来,而Java社区由于Spring和JavaEE的垄断相对要落后些,废话少说,看看这款PHP库包dudulina的特点:

1.领域模型代码最小化依赖该库包:

只需要实现三个接口,没有extends继承(接口实现高于类继承),这样你的领域代码就会保持干净,对自己运行在哪种基础架构或框架中就会毫不知情。

(1)\Dudulina\Event :每个领域事件实现这个接口; 它没有方法,它只是一个标记接口; 领域事件会被自动代码生成工具检测到;

(2)\Dudulina\Command:每个领域命令会实现这个接口; 它只有一种方法getAggregateId(); 命令调度器需要根据这个ID从Repository加载对应的Aggregate实例

(3)\Dudulina\ReadModel\ReadModelInterface:这是每个读模型需要实现的; 这仅在使用ReadModelRecreator重建读模型(预测)时才是必需的。

通过实现少数几个接口可以更加与dudulina松散耦合。可以定义和使用自己的领域接口,这个接口可以继承dudulina库包。这样,当您更改库时,只需更新这些接口就可以了。

2. 写入端的最小代码重复

在写入方面,您只需要实例化一个命令并将其发送给CommandDispatcher;

我们来创建一个命令:

// immutable and Plain PHP Object (Value Object)// No inheritance!class DoSomethingImportantCommand implements Command

{

private $idOfTheAggregate;

private $someDataInTheCommand;

public function __construct($idOfTheAggregate, $someDataInTheCommand)

{

$this->idOfTheAggregate = $this->idOfTheAggregate;

$this->someDataInTheCommand = $this->someDataInTheCommand;

}

public function getAggregateId()

{

return $this->idOfTheAggregate;

}

public function getSomeDataInTheCommand()

{

return $this->someDataInTheCommand;

}

}

创建一个简单事件:

// immutable, simple object, no inheritance, minimum dependencyclass SomethingImportantHappened implements Event

{

public function __construct($someDataInTheEvent)

{

$this->someDataInTheEvent = $someDataInTheEvent;

}

public function getSomeDataInTheEvent()

{

return $this->someDataInTheEvent;

}

}

下面是UI代码:

class SomeHttpAction

{

public function getDoSomethingImportant(RequestInterface $request)

{

$idOfTheAggregate = $request->getParsedBody()['id'];

$someDataInTheCommand = $request->getParsedBody()['data'];

$this->commandDispatcher->dispatchCommand(new DoSomethingImportantCommand(

$idOfTheAggregate,

$someDataInTheCommand

));

return new JsonResponse([

'success' => 1,

]);

}

}

只需要实现命令和事件,以及必要的UI,其他什么也不用做,就是这样,没有事务管理,不需要从存储库加载,什么也没有。命令作为一个参数传入聚合的命令处理器,如下所示:

class OurAggregate

{

//....public function handleDoSomethingImportant(DoSomethingImportantCommand $command)

{

if($this->ourStateDoesNotPermitThis()){

throw new \Exception("No no, it is not possible!");

}

yield new SomethingImportantHappened($command->getSomeDataInTheCommand());

}

public function applySomethingImportantHappened(SomethingImportantHappened $event, Metadata $metadata)

{//Metadata is optional$this->someNewState = $event->someDataInTheEvent;

}

}

读取模型将接收到上面命令处理器引发的事件,并在保存事件之后处理事件,看一看可读模型:

class SomeReadModel

{

//...some database initialization, i.e. a MongoDB database injected in the constructorpublic function onSomethingImportantHappened(SomethingImportantHappened $event, Metadata $metadata)

{

$this->database->getCollection('ourReadModel')->insertOne([

'_id' => $metadata->getAggregateId()

'someData' => $event->getSomeDataInTheEvent()

]);

}//this method could be used by the UI to display the datapublic function getSomeDataById($id)

{

$document = $this->database->getCollection('ourReadModel')->findOne([

'_id' => $metadata->getAggregateId()

]);

return $document ? $document['someData'] : null;

}

}

读模型在另外一个单独进程更新专门的读数据库,近似实时(通过tailing),或从事件存储中轮询甚至可以使用Javascript。

当前端命令到达被分派处理时时,会发生以下过程:

1. 根据Id定位到聚合实例

2. 从数据库库加载 聚合,重放所有以前的事件

3. 该命令被分派到对应聚合实例

4. 聚合产生事件

5. 事件写入保存到专门的事件数据库

6. 读模型会收到新的写入事件通知,并更新专门的读数据库

7. Safa也会被通知; 如果saga(事务管理器)产生其他命令,则循环再次开始。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值