【问题标题】:Where to put outside-aggregate validation?在哪里放置外部聚合验证?
【发布时间】:2017-12-03 10:37:13
【问题描述】:

我有一个关于外部聚合验证的问题。

  • 在我们的域合作伙伴可以下订单包含某些产品 (1)。
  • 下单后 (2) 他可以在我们的系统中将其标记为已付款 (3)。
  • 一旦订单被标记为已付款 (4),我们就会为外部库服务中的产品分配许可证 (5)。
  • 一旦我们知道分配了许可证 (6),我们就会关闭整个 saga。

这里有一张小图来说明这个过程:

此时除了命令、命令处理程序和事件之外,整个过程还涉及两个领域类:

包含业务逻辑的订单聚合 订单传奇协调整个流程并分配许可证

现在,有一个不变量尚未在此过程中建模 - 在我们将订单标记为已付款之前,我们必须检查用户是否尚未分配特定的许可证。我们也从图书馆服务中得到这个。

你会把这个验证放在哪里?命令处理程序?在某些域服务中包装订单?将一些验证器传递给 Order 构造函数?

class Order
{
    public function __construct(OrderValidator $validator)
    {
        if (!$validator->isValid($this)) {
            throw new \DomainException();
        }

        // else proceed
    }
}

class OrderValidator
{
    private $libraryServiceClient;

    public function isValid(Order $order)
    {
        // check licence using $libraryServiceClient
    }
}

【问题讨论】:

  • 如果你想要一个严格的验证,你可以传递一个“服务”,在执行 MarkPaid 命令的聚合方法中进行验证,并在更改状态之前检查它
  • 我认为用户应该是模型的一部分,因为每个订单都有一个创建它的用户。然后验证可以很简单并且仍然在聚合的一侧。用户类可以只有一个方法 ->isAllowedToMakePayment() 或 ->hasLicence()
  • @MohamedBouallegue 当然,但许可证检查实际上是不同有界上下文的一部分,所以它必须委托给某个地方 - 我的问题是如何。

标签: domain-driven-design


【解决方案1】:

据我了解,问题出在第 3 步(将订单标记为已付款)。在这一步中,我们需要一个用户(我们称之为付款人)将订单标记为已付款。因此,当创建这个付款人对象(可能使用工厂)时,我们需要知道是否允许他将订单标记为已付款。为了获取此信息,应调用外部库。

我的建议是有一个具有->markOrderAsPayed($orderId, $payerUserId) 的应用程序服务 此方法将调用 2 个域服务。一种用于获取付款人,另一种用于将订单标记为已付款。

$payer = $this->payerService->getPayer($payerUserId);
$this->orderService->payOrder($orderId, $payer);

getPayer() 函数中,您应该调用外部库以了解付款人拥有多少许可证。

我希望这会有所帮助,它只是基于我从问题和cmets中了解到的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 2013-04-24
    • 2010-09-24
    • 1970-01-01
    • 2018-02-09
    • 2018-11-09
    • 1970-01-01
    相关资源
    最近更新 更多