Where to place business logic in Symfony2?

 

Questions


After reading a lot of posts and Stack Overflow resources, I’ve still got some problems about the famous question about “where to put business logic?” Reading StackOverflow Question and A Blog Post, I believe I’ve understood the issue of code separation well.

Suppose I have a web form where you can add a user that will be added to a db. This example involves these concepts:

  • Form
  • Controller
  • Entity
  • Service
  • Repository

If I didn’t miss something, you have to create an entity with some properties, getters, setters and so on in order to make it persist into a db. If you want to fetch or write that entity, you’ll use entityManager and, for “non-canonical” query, entityRepository (that is where you can fit your “query language” query).

Now you have to define a service (that is a PHP class with a “lazy” instance) for all business logic; this is the place to put “heavy” code. Once you’ve recorded the service into your application, you can use it almost everywhere and that involves code reuse and so on.

When you render and post a form, you bind it with your entity (and with constraints of course) and use all the concepts defined above to put all together.

So, “old-me” would write a controller’s action in this way:

public function indexAction(Request $request)
    {
        $modified = False;
        if($request->getMethod() == 'POST'){ // submit, so have to modify data
            $em = $this->getDoctrine()->getEntityManager();
            $parameters = $request->request->get('User'); //form retriving
            $id = $parameters['id'];
            $user = $em->getRepository('SestanteUserBundle:User')->find($id);
            $form = $this->createForm(new UserType(), $user);
            $form->bindRequest($request);
            $em->flush();
            $modified = True;
        }

        $users = $this->getDoctrine()->getEntityManager()->getRepository('SestanteUserBundle:User')->findAll();
        return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
    }

“New-me” has refactored code in this way:

   public function indexAction(Request $request)
    {
        $um = $this->get('user_manager');
        $modified = False;
        if($request->getMethod() == 'POST'){ // submit, so have to modify data
            $user = $um->getUserById($request,False);
            $form = $this->createForm(new UserType(), $user);
            $form->bindRequest($request);
            $um->flushAll();
            $modified = True; 
        }
        $users = $um->showAllUser();
        return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
    }

Where $um is a custom service where all code that you can’t see from #1 code piece to #2 code piece is stored.

So, here are my questions:

  1. Did I, finally, get the essence of symfony2 and {M}VC in general?
  2. Is the refactor a good one? If not, what would be a better way?

Post Scriptum: I know that I can use the FOSUserBundle for User store and authentication, but this is a basic example for teach myself how to work with Symfony.
Moreover, my service was injected with ORM.Doctrine.* in order to work (just a note for who read this question with my same confusion)

 

 

————————————————-

Answer

There are two main approaches regarding on where to put the business logic: the SOA architecture and the domain-driven architecture. If your business objects (entities) are anemic, I mean, if they don’t have business logic, just getters and setters, then you will prefer SOA. However, if you build the business logic inside your business objects, then you will prefer the other. Adam Bien discusses these approaches:

Domain-driven design with Java EE 6: http://www.javaworld.com/javaworld/jw-05-2009/jw-05-domain-driven-design.html

Lean service architectures with Java EE 6: http://www.javaworld.com/javaworld/jw-04-2009/jw-04-lean-soa-with-javaee6.html

It’s Java, but you can get the idea.

model-view-controller,symfony

Facebook Comments

Post a comment