在Symfony 2 - 组合或继承中制作胖模型以及如何配置我的模型图层 [英] Making a fat model in Symfony 2 - Composition or Inheritance and how to configure my model layer

查看:200
本文介绍了在Symfony 2 - 组合或继承中制作胖模型以及如何配置我的模型图层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经到了Symfony 2 / Doctrine 2,我已经意识到,我们在服务和应用程序的应用中建立了太多的业务逻辑。控制器 - 并不足以进入模型。

I've got to the point with Symfony 2 / Doctrine 2 where I've come to realise that we have build too much business logic in our application into services & controllers - and not enough into the model.

我们希望将配置引入到我们的模型中(以修改行为),潜在地使模型直接访问服务,以便执行行为。

We wish to introduce configuration to our models (to modify behaviour) potentially giving models access to services directly in order to carry out their behaviours.

我注意到以下问题有8个upvote的标题为正确的完全错误的答案 - 所以我知道我们已经采取的方法(贫血模型)被认为是许多Symfony 2用户做的事情的正确方式。阅读更多的领域驱动设计后,我知道这不是这样的。

I've noticed that the following question has the completely wrong answer marked as correct with 8 upvotes - so I know the approach we have taken up to now (anaemic model) is considered the 'correct' way to do things by a lot of Symfony 2 users. After reading more into domain driven design I know this is not the case.

Symfony2 MVC:我的代码在哪里?

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

I see a lot of bundles define the behaviour in the model and extend this in entities/documents. This pattern works to a certain extent - but I think we need to introduce an additional stage. Some of the behaviour of our models is optional and having that behaviour will depend on what additional bundles are registered in our application (so including X bundle will allow the application to do more things). An Example.

我们有一个订单对象,目前它与快递包中的实体有双向关系,意味着有一个很强的依赖关系。我想解散它,并有快递包可选地添加行为到订单。考虑这种方法调用。

We have an order object which at the moment has a bidirectional relationship with entities in the courier bundle meaning there is a hard dependency. I want to decouple this and have the courier bundle(s) optionally add behaviour to the order. Consider this method call.

// no courier bundle is registered
$order->getShippingMethods();
// throws NoAvailableShippingMethodsException;

// one bundle registered
$order-getShippingMethods();
// returns an array with one shipping method

etc....

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

Now currently we have an OrderProvider service which just sits on top of the Entity Manager - so if you call

$orderProvider->GetOrder($id);

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

You just get the entity returned 'direct' from the database. My question here is what pattens are other people using here? I'm thinking about moving all 'business logic' into a model class that the entity extends, having the service layer pull the entity out (entity being dumb record with properties in the database and getters), and then configure the model using configuration (the configuration being injected into the OrderProvider service), which will modify the behaviour of the model. For the example given I might do something like (within the 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中的服务),并将顺序注入到该订单中。差异是微妙的,两种方法都可以工作,但我想知道哪个是最好的路径。

The other option that I have is to create a new type of object - which decorates the base order and is already configured (as it ITSELF will be defined as a service in the DIC) and inject the order into that. The difference is subtle and both approaches would work but I'm wondering which is the best path.

最后我有一个问题,所有这一切,我不能得到我的头围如果我的基本订单实体与其他实体有关系,并且需要配置THOSE实体 - 应该在哪里发生?例如,如果我访问我的客户。

Finally I have one issue with all of this that I can't get my head around. If my base Order entity has relationships with other entities and THOSE entities need to be configured - where should this happen? For example if I access my customer thus.

$order->getCustomer();

我得到客户(实体)。但是可能情况下,我还需要向客户对象添加一些配置,如

I get the customer (entity). But It may be the case that I need to add some configuration to the customer object too - like

$customer->getContactMethods();

现在,这种方法的行为可能会有所不同,具体取决于我的应用程序是否注册了一个twitter包或一个Facebook捆绑或其他东西。鉴于上述例子,我不会得到一个配置得很好的客户 - 而是香草基础实体。只有这样,我可以看到,要减少需要配置的实体之间的关系,并从CustomerProvider服务中提取实体:

Now the behaviour of this method might differ depending on whether my application has registered a twitter bundle or a facebook bundle or something else. Given the above example I'm not going to get a sufficiently configured customer - but rather the 'vanilla' base entity. Only way I can see around this is to cut relationships between entities which require configuration and pull the entity from a CustomerProvider service:

$customerProvider->getCustomerByOrder($order);

这似乎是要从模型层中删除信息,并返回依赖使用多个为简单任务提供服务(我正在努力摆脱)。

This seems to me to be removing information from the model layer and moves back towards a reliance on using multiple services for simple tasks (which I'm trying to get away from). Thoughts and links to resources appreciated.

编辑:相关 - 我看到每一天在第一个答案中列出的缺点,这就是为什么我问这个问题 - > <一个href =https://stackoverflow.com/questions/258534/anemic-domain-model-pros-cons?lq=1>贫血域模型:优点/缺点

Relevant - I see the cons listed in the first answer every single day which is why I've asked this question -> Anemic Domain Model: Pros/Cons

推荐答案

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

It seems like a complexity of your project is the modularity requirement - application behavior must be extensible via bundles. I'm not familiar with Symfony 2 / Doctrine 2 but a typical DDD tactic is to try and make sure that domain entities such as Order and Customer are unaware of bundle configurations. In other words, surrounding services should not add bundle-specific behaviors to entities. Delegating the responsibility for bundle awareness to entities will make them too complex. Fabricating entity class hierarchies to support extensive behavior is also too complex. Instead, this extensibility should be managed by application services. An application service would determine which bundles are loaded and orchestrate the appropriate entities as a result.

另一个需要考虑的策略模式是有界的上下文。是否可以将应用程序分割成与模块对齐的有界上下文?例如,要解决 $ order-getShippingMethods()方法,您可以创建两个BC,其中有一个订单模型具有 getShippingMethods( )方法和另一个没有它。有两个模型可能似乎违反 DRY ,但如果模型代表不同的东西(即一个有运送数据的订单与一个没有的订单),那么实际上没有任何重复。

Another strategic pattern to consider is bounded contexts. Is it possible to partition your application into bounded contexts which align with the modules? For example, to address the $order-getShippingMethods() method you can create two BCs, one where there is an order model that has a getShippingMethods() method and another without it. Having two models may seem like a violation of DRY but if the models represent different things (ie an order that has shipping data vs an order that doesn't) then nothing is actually repeated.

这篇关于在Symfony 2 - 组合或继承中制作胖模型以及如何配置我的模型图层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆