Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zend Framework - Doctrine 2 integration : where to store the EntityManager?

I am integrating Zend Framework and Doctrine 2.

The question is, in my controllers and view, in need to access the model. I can do all this through a single instance of the EntityManager.

Where do I store this instance ?

  • Zend_Registry ? That's where it is now, it is accessible from everywhere, but not really practical : $em = Zend_Registry::get('EntityManager');
  • As a controller and view property ? That would be accessible as $this->em, I like this
  • Create a factory class that will return the instance ? $em = My\EntityManager\Factory::getInstance();. Encapsulation is good, but long to type...
  • Is the EntityManager a Singleton already ? -> (update) not it is not
like image 610
Matthieu Napoli Avatar asked Apr 29 '11 17:04

Matthieu Napoli


3 Answers

I wouldn't recommend using the EntityManager directly in your Controllers and Views. Instead, use a Service layer and inject the EntityManager it that.

I have two custom action helpers, one to retrieve Repositories and one for Services. Each action hold a reference to the EntityManager and inject it accordingly before handing it back to the Controller.

Not my actual code but something like this (not tested):

My/Controller/Action/Helper/Service.php

<?php

namespace My\Controller\Action\Helper;

use Doctrine\ORM\EntityManager;

class Service extends \Zend_Controller_Action_Helper_Abstract
{

    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function direct($serviceClass)
    {
        return new $serviceClass($this->em);
    }

}

You can write a similar Action Helper to retrieve Repositories.

Then, register the helper in your bootstrap (where we also have access to the EntityManager):

<?php

use Zend_Controller_Action_HelperBroker as HelperBroker,
    My\Controller\Action\Helper\Service;

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{

    public function _initActionHelpers()
    {
        $this->bootstrap('doctrine');
        $em = $this->getResource('doctrine');

        HelperBroker::addHelper(new Service($em));
    }

}

Now write a simple Service.

My/Domain/Blog/Service/PostService.php

<?php

namespace My\Domain\Blog\Service;

use Doctrine\ORM\EntityManager,
    My\Domain\Blog\Entity\Post;

class PostService implements \My\Domain\Service
{

    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function createPost($data)
    {
        $post = new Post();
        $post->setTitle($data['title']);
        $post->setContent($data['content']);

        $this->em->persist($post);
        $this->em->flush(); // flush now so we can get Post ID

        return $post;
    }

}

And to bring it all together in a controller action:

<?php

class Blog_PostController extends Zend_Controller_Action
{

    private $postService;

    public function init()
    {
        $this->postService = $this->_helper->Service('My\Domain\Blog\PostService');
    }

    public function createPostAction()
    {
        // normally we'd get data from the actual request
        $data = array(
            "title" => "StackOverflow is great!",
            "content" => "Imagine where I'd be without SO :)"
        );
        // and then validate it too!!

        $post = $this->postService->createPost($data);
        echo $post->getId(); // Blog post should be persisted
    }

}
like image 122
Cobby Avatar answered Nov 12 '22 20:11

Cobby


Since the EntityManager is usually created and configured during bootstrap - either as the return value of an explicit _initDoctrine() call or by using an application resource - storing it in the Bootstrap seems to make the most sense to me. Then inside a controller, it is accessible as:

$em = $this->getInvokeArg('bootstrap')->getResource('doctrine');

I see a lot of examples of accessing bootstrap via the front controller singleton:

$em = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('doctrine');

which has the advantage that works everywhere.

like image 28
David Weinraub Avatar answered Nov 12 '22 19:11

David Weinraub


Take a look at the integration provided by the Bisna package, written by one of the Doctrine 2 contributes. It is at https://github.com/guilhermeblanco/ZendFramework1-Doctrine2

It allows you to configure Doctrine in your application.ini. It uses an application resource plugin to process the ini settings. I have written documentation for Bisna. It may be integrated into the package by the time you read this. If not, you can find it at https://github.com/kkruecke/ZendFramework1-Doctrine2, in the bisna-documentation/html subdirectory of that package. I have also put the documentation a http://www.kurttest.com/zfa/bisna.html (although this may be temporary).

like image 30
kkruecke Avatar answered Nov 12 '22 21:11

kkruecke