2

I am new to ZendFramework 2 and the whole DI idea.

Here is what I need to achieve:

  1. Create many Model classes extending a single AbstractModel
  2. Supply that AbstractModel using DI with dependencies (in my case the doctrine entity manager)
  3. Use the ancestor classes wherever I need them as normal classes

To better explain 3. lets see this example:

class Ancestor extends Parent { }

In a controller, or ideally anywhere:

$ancestor = new Ancestor();
$ancestor->doStuffWithEntityManager();

Uppon initializing ancestor it must already be aware of the injected resources.

Is this even possible? If not use in it's default form I am ok with initializing the ancestor via some service managers etc. as long as I don't need to specify each and every ancestor. I need to tell zend: inject this and that into every class that extends/implements X.

Any ideas?

P.S.: As I said I am quite new, so please specify the configuration/class file I must add each piece of example code.

Tony Bogdanov
  • 7,436
  • 10
  • 49
  • 80

3 Answers3

6

In my architecture i do it like the following. First: I create a Service:

class Module 
{
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'my-service-name'   => 'MyNamespace\Factory\MyServiceFactory'
            )
        );
    }
}

Then i create the ServiceFactory. This will be the point where all dependencies will be taken care of.

<?php
namespace MyNamespace\Factory;

use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
use MyNamespace\Service\SomeService;

class MyServiceFactory implements FactoryInterface
{
    /**
     * Create service
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return \MyNamespace\Service\SomeService
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $service = new SomeService();
        $service->setEntityManager($serviceLocator->get('Doctrine\ORM\EntityManager'));
        return $service;
    }
}

The MyService-Class can have even morde dependencies, which in my case get automatically injected due to the interfaces they implement. You can see an example right here. A specific EntityService then would only need one function defining the repository like this example here.

You may also be adviced to read Rob Allens introduction to ServiceManager Configuration Keys. Specifically read about the 'initializers' section, i guess this is your questions main-concern?

I hope this covers your question.

Sam
  • 16,435
  • 6
  • 55
  • 89
  • Quite. My implementation (currently works) is similar. I register a db service and define a `get($class)` method in it. Then I call the service's get method in controller with the model class I need. The service factory creates an instance and injects the dependencies I specify. I'm not sure this is proper DI, but I guess it will suffice. – Tony Bogdanov Nov 16 '12 at 09:29
  • @Sam Do you have any solution for cases with circular dependencies? For example in your answer, what if `Doctrine\ORM\EntityManager` required an instance of `SomeService`? There would be a never ending recursive loop. – james Dec 02 '16 at 20:15
  • @binnyb that sounds like bad design :) There's not really a solution to that other than to refactor the dependencies into stuff that makes sense. Proper examamples may be required to aid you with this. – Sam Dec 06 '16 at 10:51
1

You can inject the entity manager creating a custom repository class and inject it overriding find* method calls

Using EntityManager inside Doctrine 2.0 entities

However I suggest you review your design because it's not normal call to a database from the entity

Community
  • 1
  • 1
Maks3w
  • 6,014
  • 6
  • 37
  • 42
-1
class Parent {
    private $em;

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

class Ancestor extends Parent { }

// To use, create an EntityManager $em

$ancestor = new Ancestor($em);
$ancestor->doStuffWithEntityManager(); // Uses $this->em internally

That's really all there's to Dependency Injection. See also http://fabien.potencier.org/article/11/what-is-dependency-injection.

Check here for getting/creating an EntityManager in ZF2: http://samminds.com/2012/07/a-blog-application-part-1-working-with-doctrine-2-in-zend-framework-2/.

Essentially, in a controller extended from AbstractActionController you can do:

$this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
aderuwe
  • 1,013
  • 8
  • 11
  • If the documentation was understandable or appliable in the real world I wouldn't have asked here. `create an EntityManager $em somehow` is exactly what I don't know how to do. – Tony Bogdanov Nov 16 '12 at 08:30
  • Ok, I've clarified it hopefully. – aderuwe Nov 16 '12 at 08:39
  • Well no, because your code isn't actually DI. It's just creating an object and passing the entity manager as parameter to the constructor. Besides I am familiar with the idea of DI, what I don't know is how to make zf2 use it's configuration to do all the heavy lifting for me. – Tony Bogdanov Nov 16 '12 at 08:51
  • The code above is exactly what DI is. "It's just creating an object and passing the entity manager as parameter to the constructor". That's called constructor injection, one of two ways of doing DI. – aderuwe Nov 16 '12 at 08:54
  • Still it doesn't relate to my question. – Tony Bogdanov Nov 16 '12 at 08:56