0
votes

Edit 1: it seems like I didn't explain myself very well. Class Foo is not an entity. Just a general purpose model that I would like to have an access to the entity manager.

Edit 2: I don't think there is an answer to my question. Basically, I wanted a class that can have access to the EntityManager without this class being called by the service manager, simply due to the fact that it may be called by a class who is also not called by the service manager. In other words, I was trying to achieve what Zend_Registry used to achieve in ZF1. I'll have to find another way of doing what I am trying to do.

I am trying to access Doctrine's entity manager in a model, in a similar way as it done in a controller:

$this->getServiceLocator()->get('Doctrine\ORM\EntityManager');

The ZF2 manual (http://framework.zend.com/manual/2.0/en/modules/zend.service-manager.quick-start.html) says:

By default, the Zend Framework MVC registers an initializer that will inject the ServiceManager instance, which is an implementation of Zend\ServiceManager\ServiceLocatorInterface, into any class implementing Zend\ServiceManager\ServiceLocatorAwareInterface.

So I created a the following class:

<?php
namespace MyModule\Model;

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class Foo implements ServiceLocatorAwareInterface
{
    protected $services;

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
         $this->services = $serviceLocator;
    }

    public function getServiceLocator()
    {
         return $this->services;
    }

    public function test()
    {
        $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
    }
}   

Then, from another class I call this class as such:

$foo = new \MyModule\Model\Foo();
$foo->test()

which throws the following error:

PHP Fatal error: Call to a member function get() on a non-object

So, I guess I am missing something somewhere, but what? Where? How? Perhaps there is an easier to access the entity manager?

Thanks!

2
You should not use the entity manager inside of an doctrine entity. Doctrine 2 entities are just data storages for actions on the tables you may want to look at custom repository classes which have access to the entity manager. If you provide an example of what you want to do with the entity manager inside of the entity I may be able to help you find the proper way to do this. As of your question it should only be inistialized if you use the service locator/DI to get your entity.Hikaru-Shindo
I recommend you not to retrieve the EM manually in any class as this will give you a time creating unit tests. Also, if you change the service alias (doctrine.entitymanager.orm_default) in future, you'll need to refactor everything. Btw, you're creating the instance using the new keyword. ZF2 can only inject dependencies if you use the ServiceManager and/or Di.Daniel M
Ah yes there were unit tests too. But to have the entity manager inside of the entity is even worst of design Daniel M. It's discouraged by the doctrine team since it's much against doctrine's design pattern. The entity is just a data storage - not more, not less. The first answer on this question: stackoverflow.com/questions/4108291/… describes the problem really good I think.Hikaru-Shindo
Who said anything about entity manager in entities? The question, if it wasn't clear, was about accessing the entity manager from a general purpose class.user1510297
Daniel M: thanks. Your comment about not using the new keyword at least give me a direction to investigate further.user1510297

2 Answers

1
votes

From your question, I see that you have mainly two misunderstandings, one about your design strategy (injecting an EntityManager on your model) and one about how things work with the service manager (ServiceLocatorAwareInterface). In my answer I'll try to focus on the second one.

Initializers are php closures that are called over each instance accessed from the Service Manager before this one returns it to you.

Here is an example of an Initializer :

// Line 146 - 150 of Zend\Mvc\Service\ServiceManagerConfig class + comments

$serviceManager->addInitializer(function ($instance) use ($serviceManager) {
        if ($instance instanceof ServiceManagerAwareInterface) {
            $instance->setServiceManager($serviceManager);
        }
    });

As you can see each time Service Manager is asked to return an instance/object that implements the ServiceManagerAwareInterface interface, it will setup/inject the Service Manager instance to it.

By the way in your previous code you omitted to implement correctly the interface as you didn't define the setServiceManager method. However, this is not your only problem. First, if you want the Service Manager to inject itself in your Model, you need to call/construct your model instance from it (during this process it will call the initializers) through a factory for example if your class has complex dependencies.

[EDIT]

Example:

In your MyModule

namespace MyModule;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use MyModule\Model\Foo;

class Module implements ServiceProviderInterface{

//Previous code

public function getServiceConfig()
{
    return array(
        'instances' => array(
            'myModelClass'        => new Foo(),
            ),
       );

}

Now, when you need a Foo instance you should call the Service Manager:

$serviceManager->get('myModelClass');

Don't forget defining setServiceManager method, otherwise your'e not correctly implementing the ServiceManagerAwareInterface!

1
votes

I think, the only thing you’re missing, is to add your model class to the list of invokables and retreive it through the service manager.

So basically add this to your module.conf.php:

return array(
    'service_manager' => array(
        'invokables' => array(
            'MyModule\Model\Foo' => 'MyModule\Model\Foo',
        ),
    ),
);

And instantiate your model object like this (if in a controller):

$foo = $this->getServiceLocator()->get('MyModule\Model\Foo');
$foo->test();