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