Creating a fat model in Symfony 2 - Composition or Inheritance and how to set up my model layer

I have a point with Symfony 2 / Doctrine 2 where I realized that we created too much business logic in our application in services and controllers - and this is not enough for the model.

We want to inject configuration into our models (to change behavior), potentially giving models access to services directly to execute their behavior.

I noticed that the following question has a completely incorrect answer, marked as correct with 8 upvotes - so I know that the approach we have taken so far (anemic model) is considered the โ€œrightโ€ way to do things through many Symfony 2 users. After of how I read more about the domain, I know that this is not so.

Symfony2 MVC: where does my code belong?

I see that many packages define behavior in the model and extend it into entities / documents. This model works to a certain extent - but I think we need to introduce an additional step. Some behavior of our models is optional, and such behavior will depend on what additional packages are registered in our application (so the inclusion of an X-package will allow the application to do more things). Example.

We have an object of order, which at the moment has a bi-directional connection with the entities in the package of couriers, which means that there is a hard dependency. I want to separate this and you have a courier kit (s) that can add behavior 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.... 

Now we have the OrderProvider service, which is simply on top of the Entity Manager, so if you call

 $orderProvider->GetOrder($id); 

You just get the object that was returned by 'direct' from the database. My question here is what other people use here? Iโ€™m thinking about moving all the โ€œbusiness logicโ€ to a model class that extends the object when the service level pulls out the object (the entity is a blank record with properties in the database and getters), and then configures the model using the configuration (the configuration entered into the service OrderProvider), which will change the behavior of the model. In the above example, I could do something like (inside 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; } 

Another option that I have is to create a new type of object - which decorates the basic order and is already configured (since ITSELF will be defined as a service in the DIC) and enter the order in it. The difference is subtle, and both approaches will work, but I wonder which one is the best way.

Finally, I have one problem with all of this that I cannot lower my head. If my base Order object has relationships with other objects, and these objects need to be configured - where should this happen? For example, if I contact my client this way.

 $order->getCustomer(); 

I get a client (entity). But it may be that I need to add some configuration to the client object - for example

 $customer->getContactMethods(); 

Now, the behavior of this method may vary depending on whether my application is registered with Twitter or facebook, or something else. Given the above example, I am not going to get a sufficiently configured client, but rather the base 'vanilla' object. The only way I can see this is to crop the relationships between objects that require configuration and pull the object out of the CustomerProvider service:

 $customerProvider->getCustomerByOrder($order); 

It seems to me that I am deleting information from the model level and will return to using several services for simple tasks (which I am trying to leave). Thoughts and links to resources appreciated.

Edit: Relevant - I see the cons listed in the first answer every day, so I asked this question โ†’ Anemic domain model: pros / cons

+4
source share
1 answer

It seems that the complexity of your project - a requirement of modularity - the behavior of the application should expand through packages. I am not familiar with Symfony 2 / Doctrine 2, but a typical DDD tactic is to try to make sure that domain objects such as Order and Customer are not aware of package configurations. In other words, the surrounding services should not add package-specific behavior to objects. Delegating responsibility for knowledge of entity relationships will make them too complex. The hierarchy of object classes to support extensive behavior is also too complex. Instead, this extensibility should be managed by application services. The application service will determine which packages are downloaded, and as a result, create the appropriate objects.

Another strategic template to consider is limited contexts . Is it possible to break your application into limited contexts that coincide with modules? For example, to refer to the $order-getShippingMethods() method, you can create two $order-getShippingMethods() where there is an order model that has the getShippingMethods() method and the other without it. The presence of two models may seem to be a violation of DRY , but if the models represent different things (i.e., an order that has delivery data compared to order, t), then nothing is actually repeated.

0
source

All Articles