0

In a Zend Framework 2 app, I have some Doctrine2 entities that have dependencies, which are injected into them by the ServiceManager, i. e. an Order needs a new Invoice whenever it is created.

'service_manager' => [
    'invokables' => [
        'Sales\Entity\Invoice' => 'Sales\Entity\Invoice'
    ],
    'factories' => [
        'Sales\Entity\Order' => function($sm) {
            $order = new \Sales\Entity\Order();
            $order->setInvoice($sm->get('Sales\Entity\Invoice'));
            return $order;
        }
    ],
    'shared' => [
        'Sales\Entity\Invoice' => false,
        'Sales\Entity\Order' => false
    ]
]

With this configuration, it is no problem to create a new Order that has a new Invoice assigned to it anywhere in the application, because for example inside a controller I can just call

$order = $this->getServiceLocator()->get('serviceManager')->get('Sales\Entity\Order');

However, when retrieving an Order via an EntityRepository, the dependencies won't be injected because as far as I know, Doctrine instantiates an entity by calling its constructor and then cloning this instance whenever it needs another one. Doctrine thereby bypasses the ServiceManager and hence the dependency injection.

I. e.

$order = $entityManager->getRepository('Sales\Entity\Order')->find(42);

will give me an order without a new Invoice.

I know directly injecting dependencies into entities might not be the best solution, but at this moment we are working with fat models in our application without a model service layer and for a quick fix, I have to get this to work. Refactorings are planned for the future but are not up for discussion right now.

Is it possible to change the way Doctrine instantiates a new entity? I dipped into the EntityManager and EntityRepository, but have not yet found a solution.

Wilt
  • 41,477
  • 12
  • 152
  • 203
Subsurf
  • 1,256
  • 1
  • 17
  • 28
  • 1
    Nope. Not practical to change Doctrine (which by the way uses reflection and never actually calls the entity construct method at all). But find(42) loads an existing order, it does not create one, so it should always have an invoice anyways. The invoice may need to be lazy loaded but it should be there. I suppose you could use a postLoad listener (http://symfony.com/doc/current/components/routing/introduction.html#usage) but you should not need to. – Cerad Feb 03 '16 at 13:15
  • Yeah I built a workaround with the postLoad event now... it's defenitely time to implement a model service layer... – Subsurf Feb 03 '16 at 13:59
  • Still seems a bit strange the orders require an invoice but you seem to have stored orders without one. But you know your model best. – Cerad Feb 03 '16 at 14:21

0 Answers0