在Symfony 2中制作一个胖模型-组合或继承,以及如何配置我的模型层



我已经谈到了Symfony 2/Doctrine 2的要点,在那里我意识到我们在应用程序中将太多的业务逻辑构建为服务&控制器-而且对模型的了解还不够。

我们希望在我们的模型中引入配置(以修改行为),这可能会让模型直接访问服务,以执行其行为。

我注意到以下问题的答案完全错误,有8张赞成票,标记为正确-所以我知道我们目前采用的方法(贫血模型)被许多Symfony 2用户认为是"正确"的做事方式。在阅读了更多关于领域驱动设计的内容后,我知道事实并非如此。

Symfony2 MVC:我的代码属于哪里?

我看到很多bundle定义了模型中的行为,并在实体/文档中进行了扩展。这种模式在一定程度上有效,但我认为我们需要引入一个额外的阶段。我们模型的一些行为是可选的,具有这种行为将取决于在我们的应用程序中注册了哪些附加捆绑包(因此包括X捆绑包将允许应用程序做更多的事情)。一个例子。

我们有一个订单对象,它目前与快递包中的实体有双向关系,这意味着存在硬依赖关系。我想将其解耦,并让快递捆绑包选择性地将行为添加到订单中。请考虑此方法调用。

// no courier bundle is registered
$order->getShippingMethods();
// throws NoAvailableShippingMethodsException;
// one bundle registered
$order-getShippingMethods();
// returns an array with one shipping method
etc....

现在,我们有一个OrderProvider服务,它位于实体管理器的顶部,所以如果你调用

$orderProvider->GetOrder($id);

您只需要从数据库中直接返回实体。我的问题是其他人在这里用什么馅饼?我正在考虑将所有的"业务逻辑"移动到实体扩展的模型类中,让服务层将实体拉出(实体是数据库和getter中具有属性的哑记录),然后使用配置(将配置注入OrderProvider服务)配置模型,这将修改模型的行为。对于给定的示例,我可能会(在OrderProvider中)执行以下操作。。

// trimmed down for example purposes by removing exceptions etc.
public function getOrder($id) 
{
$order = $this->orderRepository->findOneById($id);
if ($this->couriers){
$order->addCouriers($couriers);
}
return $order;
}
// this function would be called by the courier bundle automatically using semantic configuration / tags / setter injection
public function addCourier(CourierInterface $courier)
{
$this->couriers[] = $courier;
}

我的另一个选择是创建一种新类型的对象,它修饰了基本顺序,并且已经配置好了(因为ITSELF将被定义为DIC中的一个服务),并将顺序注入其中。区别很微妙,两种方法都可行,但我想知道哪条路是最好的。

最后,我对这一切有一个问题,我无法理解。如果我的基本订单实体与其他实体有关系,并且需要配置这些实体,那么应该在哪里进行配置?例如,如果我这样访问我的客户。

$order->getCustomer();

我得到客户(实体)。但可能我也需要为客户对象添加一些配置,比如

$customer->getContactMethods();

现在,这种方法的行为可能会有所不同,这取决于我的应用程序是否注册了twitter捆绑包、facebook捆绑包或其他什么。在上面的例子中,我不会得到一个配置充分的客户,而是"香草"基础实体。我能看到的唯一方法是切断需要配置的实体之间的关系,并从CustomerProvider服务中提取实体:

$customerProvider->getCustomerByOrder($order);

在我看来,这似乎是在从模型层中删除信息,并重新转向对使用多个服务执行简单任务的依赖(我正试图摆脱这种依赖)。思想和资源链接受到赞赏。

编辑:相关-我每天都会看到第一个答案中列出的缺点,这就是我问这个问题的原因->贫血领域模型:优点/缺点

项目的复杂性似乎在于模块化需求——应用程序行为必须通过捆绑包进行扩展。我不熟悉Symfony 2/Doctrine 2,但一种典型的DDD策略是尝试确保Order和Customer等域实体不知道捆绑包配置。换句话说,周围的服务不应该向实体添加捆绑包特定的行为。将捆绑包意识的责任委托给实体会使其过于复杂。构造实体类层次结构以支持广泛的行为也过于复杂。相反,这种可扩展性应该由应用程序服务来管理。应用程序服务将确定加载了哪些捆绑包,并因此编排适当的实体。

另一个需要考虑的战略模式是有限的上下文。是否可以将您的应用程序划分为与模块对齐的有界上下文?例如,为了解决$order-getShippingMethods()方法,你可以创建两个BC,一个有一个有getShippingMethods()方法的订单模型,另一个没有。有两个模型可能看起来违反了DRY,但如果模型代表不同的东西(即有发货数据的订单和没有发货数据的单单),那么实际上什么都不会重复。

相关内容

  • 没有找到相关文章

最新更新