我想在PHP中制作CQRS事件源应用程序。我想知道,把聚合根(AbstractItem
在下面的例子中)放入在db中序列化的事件是否可行? (我想没有,但什么是另类?)比如我有命令处理程序AddItemToCartCommand
与该句柄方法:如何在事件存储中对事件进行序列化/反序列化,并且将聚合根存储在它们中是如此糟糕?
public function handle(Command $command)
{
Assertion::isInstanceOf($command, AddItemToCartCommand::class);
$cart = $this->loadCart($command->getCartId());
$item = $this->loadItem($command->getItemId());
$cart->addItem($item);
$this->eventRepository->save($cart);
}
而Cart
和AbstractItem
是总根源。 我Cart
AR实现这种方式:
class Cart extends AggregateRoot
{
/** @var UuidInterface */
private $customerId;
/** @var AbstractItem[] */
private $items;
public function __construct(UuidInterface $cartId, UuidInterface $customerId)
{
$this->apply(new EmptyCartCreated($cartId, $customerId));
}
public function addItem(AbstractCartItem $item)
{
$this->apply(new ItemToCartAdded($this->getId(), $item));
}
protected function applyEmptyCartCreated(EmptyCartCreated $event)
{
$this->setId($event->getCartId());
$this->customerId = $event->getCustomerId();
}
protected function applyItemToCartAdded(ItemToCartAdded $event)
{
$item = $event->getItem();
$this->items[(string) $item->getId()] = $item;
}
}
现在,问题是ItemToCartAdded
事件具有这种结构:
class ItemToCartAdded extends AbstractDomainEvent
{
/** @var UuidInterface */
protected $cartId;
/** @var AbstractItem */
protected $item;
public function __construct(UuidInterface $cartId, AbstractItem $item)
{
$this->cartId = $cartId;
$this->item = $item;
}
public function getCartId(): UuidInterface
{
return $this->cartId;
}
public function getItem(): AbstractItem
{
return $this->item;
}
}
也许我应该,而有一些DTO对象持有AbstractItem
数据,而不是AbstractItem
AR本身在ItemToCartAdded
事件中。然后我会在applyItemToCartAdded
方法中根据那些DTO数据实例化新的对象AbstractItem
。
但由于项目是抽象类,我不知道我需要实例化什么实现。当然,我可以在那个DTO中有班级名称,所以我知道然后以某种方式破解它。但似乎有点矫枉过正,因为我在AbstractItem
上有私有构造函数,并在特定实现中使用工厂方法。
另一方面,序列化整个聚合根带我到序列化的问题:当我序列化AR时,我需要反序列化在某些时候,但我该怎么做?我知道有反射,但它是丑陋的黑客,绕过我的反序列化AR验证,因此我可能最终以某种方式无效的AR可能陷入噩梦。或不?
我应该如何序列化和反序列化我的事件以很好地解决此问题?也许我可以在ItemToCartAdded
事件中找到这两个聚合的ID,但是我不能将这个事件应用到购物车AR,以便它拥有AbstractItem
(最终保护我的一些不变量)列表。我最终会在购物车AR中列出物品ID列表,因为我当然没有在我的AR中访问存储库。
我的问题在哪里,或者我错了什么?
顺便说一句,我使用这个库是叉:https://github.com/beberlei/litecqrs-php
你可以看看另一个CQRS + ES库PHP这里https://github.com/xprt64/todosample-cqrs-es在这个库事件从'Aggregate'被'产生',然后持续到'EventStore'。免责声明:我已经做到了:) –
@ConstantinGALBENU我检查了你的框架,顺便把命令直接传递给聚合是一个有趣的方法,但是我需要质疑,是否真的需要某个AR负责每个特定的命令?我认为在绝大多数时候是的,但真的是每次? :) – Tom
@ConstantinGALBENU聚合产生事件是很好的方法,但我不明白他们应该如何解决我的问题:(我的问题是,我的购物车AR由'AbstractItem' ARs(它们也可以不存在'Cart' ),并且我需要将它们放入购物车中。对于您的库,我会遇到类似的问题:我需要将'AbstractItem' AR添加到'AddItemToCartCommand'(这是无稽之谈),或者是所有数据都能够重新实例化购物车AR处理程序 - 这听起来更好,但恢复AR而不是从存储库(不是在AR处理程序中)听起来很奇怪 – Tom