9

I've a question related to Doctrine 2 and Zend Framework.

If you use Zend Framework without Doctrine by default you place business logic in the models. But as Doctrine 2 does have Entities where should the business logic be placed?

I first had created models where the entity manager did calls to the Entities. But when I wanted to write unit tests for my models without database calls. I needed to move the entity manager to the controllers. But I'm getting business logic in my controllers which is not good.

The code below shows a part of an controller action:

        $customerAddress = $this->_model->save($values, $id);

        $this->_em->persist($customerAddress);

        // Update default billing address
        $defaultBilling = $this->_model->saveDefaultBilling($values, $customerAddress);
        if ($defaultBilling != FALSE) {
            $this->_em->persist($defaultBilling);
        }

        // Update default shipping address
        $defaultShipping = $this->_model->saveDefaultShipping($values, $customerAddress);
        if ($defaultShipping != FALSE) {
            $this->_em->persist($defaultShipping);
        }

        $this->_em->flush();

Can somebody say what's the best practice for this issue? Thx

tom
  • 8,189
  • 12
  • 51
  • 70
  • I think it's best that all Doctrine code is shifted out of controllers and into domain classes, please check my blog post: http://www.cobbweb.me/2010/11/integrate-doctrine-2-zend-framework-application/ – Cobby Nov 23 '10 at 00:15

2 Answers2

13

I'm not sure there is an agreed upon best practice, but I see a lot of talk regarding Service Layers when discussing Doctrine or Zend Framework.

When I started my app with Doctrine, I tried to build as much functionality into my Entity objects as I could, but quickly realized that's almost impossible without injecting the Entity Manager, which totally breaks the idea of plain, non-persistence-aware objects that makes Doctrine 2 so nice.

If you're coming from an Active Record world, it's easy to think of your 'model' as single object that corresponds to a database table and that controllers have to talk to these objects. This is usually okay for very simple CRUD applications. But because of Doctrine's approach, doing it that way is weird and frustrating.

Instead, think of the different layers in your application. Doctrine is a layer that sits on top of the database, your Entities sit on top of Doctrine, and your Service Layer should sit on top of your Entities. That whole package is your M in MVC, and it comprises both data persistence and business logic.

I would suggest you check out this presentation on the topic.

UPDATE

I originally missed the part where you mentioned you had separate model objects making calls to the Entities. I think that would be an acceptable pattern to use. If you want to write tests without making database calls, you're probably going to want to to use a mock of the Entity Manager -- it's a dependency no matter which layer you put it in.

Bryan M.
  • 17,142
  • 8
  • 46
  • 60
  • I think the trick here is to design your model so it is persistence agnostic, i.e. it could have been instantiated entirely by calling new all over the place and setting properties from literals. Every needed object in every collaboration should then be accessible by traversing the object graph (through the object references created by doctrine's relationship mappings) thus the entity manager shouldn't be needed in the entities. – Ezequiel Muns Feb 19 '13 at 23:32
2

Here is the github skeleton project I used, it did the doctrine 2 initialisation with Zend Franework 1.11.2 in the bootstrap, nice and clean, using model for entities & model repository for business logic. Unit tests & ant build script too for you TDD developers out there.

https://github.com/eddiejaoude/Zend-Framework--Doctrine-ORM--PHPUnit--Ant--Jenkins-CI--TDD-

zoom
  • 21
  • 1