Code separation in symfony 2 - Controller vs Service vs entity

I am using symfony 2 and I have a question about code splitting. I would like to make sure that I understand correctly what elements should be in the controller, what is in the service and what is in essence.

Suppose I have a list of documents that I need to display. In each document, before displaying, I must also perform some logical operation (for example, add two variables).

As in understanding the entity class, it only cares about finding and working with data on a single object. I should not enter any custom code there. As I understand it, this should be done by the service.

But should I:

  • use the service to go to the list of controllers based on some criteria after completing the required logic,
  • or use a controller to load a list of documents, and then go through a document for maintenance to execute some logic?

I would prefer the first approach to match the thin controller (thin controllers, large models), but is this approach true? What code should be in essence, what is in the controller and what is in the service?

In particular, where should I relate to the entity manager - in the controller or, rather, in the service?

Let me also pretend that in many places in my application I need to check if the document is complete before allowing the user to perform any action (for example, edit it). It should definitely be either in the service, since another service will be required to verify this. Should I upload the document object object to the controller, send it to the service to check if it can be completed or, rather, upload the document to the service and perform the check?

+6
source share
3 answers

My Symfony 2 architecture (with Doctrine ORM):

  • Thin controllers with routing logic
  • Service (aka "Manager") for each object (all business logic is here).
  • Custom services for my other needs (i.e. for using external tools like Amazon S3 or Mandrill)
  • Repository for each object (read only objects from the database)

Each action inside the controller calls one or more methods from the entity manager; I always try to avoid using the repository of "magic methods" directly in favor of custom methods: inside an action instead of calling

 $this->getDoctrine()->getRepository(<entity>)->findBy(array('parent' => null)); 

I create this method inside the repository:

 public function findParents() { return $this->findBy(array('parent' => null)); } 

And inside the action I use:

 $this->getDoctrine()->getRepository(<entity>)->findParents(); 

Of course, this is a simple example, but it works great with more complex findBy or findOneBy .

+9
source

Symfony2 has a very simple decoupling logic using repositories and services. For instance:

Object repository with additional custom search

 use Doctrine\ORM\EntityRepository; class MyEntityRepository extends EntityRepository { public function findAllWithX($parameter) { // your DQL. manipule own data. filters. } } 

Thick service for processing core business logic

 // could be a listener class MyFatService { public function __construct(MyEntityRepository $mer, AnotherRepository $aor, MisteriousService $mis) { $this->mer = $mer; $this->aor = $aor; $this->mis = $mis; } public function someBigAction($paramX, $paramY) { $foo = $this->mer->findAllWithX($paramX); $bar = $this->aor->findBy(....); // manipule data. complex operations. // call related services. // manipule data related to many repositories } } 

To define services:

 services: my_entity_repository: class: AppBundle\Repository\MyEntityRepository factory: [@doctrine, getRepository] arguments: - %entity.my_entity% my_another_repository: class: AppBundle\Repository\AnotherRepository factory: [@doctrine, getRepository] arguments: - %entity.my_another_entity% my_fat_service: class: AppBundle\MyFatService arguments: - @my_entity_repository - @my_another_repository - @misterious_service 

In your controller:

 public function blaAction($x, $y) { // leave the heavy work to services. // just handle request and send the response $data = $this->get('my_fat_service') ->someBigAction($x, $y); return $this->render('template.twig', ['data' => $data]); } 

ps: sorry for my english

+7
source

But should I:

use the service to go to the list of controllers based on some criteria after completing the required logic, or use the controller to upload a list of documents, and not transfer documents for maintenance to execute some logic?

Rather, the second. Just because it allows you to understand what is happening by looking at your controller code. It is assumed that all web frameworks should display every request for a controller action. Following this logic, waiting for a request, you go to the controller. I would suggest you directly call the service in the controller in order to execute some custom data logic. But if you need to extract data from a database, it is better to implement a repository in your class not in the service.

If you need to reorganize your data after extraction, you may need to rethink the structure of your database. It is much simpler and much more convenient to be able to extract what you need without any action after extraction.

I would prefer the first approach to match the controller thin (thin controllers, large models), but is this approach correct? What code should be in essence, what is in the controller and what is in the service?

To keep the controller thin, it’s enough not to introduce queries and other complex logic into it: for example, sorting, filtering, etc.

In particular, where should I relate to the entity manager - in the controller or, rather, in maintenance?

This is also pretty easy. You should relate to them where you need to. There is nothing wrong if your logic is not complicated, and the only need you have before displaying the result is to make very tiny material (for example, to set some kind of virtual property for the resulting object), which is absolutely normal to enable this logic to the controller. But don't forget to reorganize your code with complexity. If it becomes a code that should be used in different places (repeated code), exit the controller to the service.

+1
source

All Articles