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

查看:182
本文介绍了在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: where does my code belong?

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

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.

我们有一个订单对象,它目前与快递包中的实体有双向关系,意味着有一个硬依赖。我想解耦这个,并有快递包(s)可选择添加行为的顺序。考虑这个方法调用。

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);

您只需要从数据库中返回direct我的问题是什么pattens是其他人在这里使用?我正在考虑将所有的业务逻辑移动到实体扩展的模型类中,让服务层拉出实体(实体是具有数据库和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.

编辑:相关 - 我看到每一天的第一个答案中列出的缺点,这就是为什么我问过这个问题 - > < a href =http://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配置。换句话说,周边服务不应该向实体添加bundle特定的行为。将对团体意识的责任委托给实体将使其过于复杂。制造实体类层次结构以支持广泛的行为也太复杂。相反,这种可扩展性应该由应用程序服务来管理。应用程序服务将确定加载哪些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天全站免登陆