98

I've created my own service and I need to inject doctrine EntityManager, but I don't see that __construct() is called on my service, and injection doesn't work.

Here is the code and configs:

<?php

namespace Test\CommonBundle\Services;
use Doctrine\ORM\EntityManager;

class UserService {

    /**
     *
     * @var EntityManager 
     */
    protected $em;

    public function __constructor(EntityManager $entityManager)
    {
        var_dump($entityManager);
        exit(); // I've never saw it happen, looks like constructor never called
        $this->em = $entityManager;
    }

    public function getUser($userId){
       var_dump($this->em ); // outputs null  
    }

}

Here is services.yml in my bundle

services:
  test.common.userservice:
    class:  Test\CommonBundle\Services\UserService
    arguments: 
        entityManager: "@doctrine.orm.entity_manager"

I've imported that .yml in config.yml in my app like that

imports:
    # a few lines skipped, not relevant here, i think
    - { resource: "@TestCommonBundle/Resources/config/services.yml" }

And when I call service in controller

    $userservice = $this->get('test.common.userservice');
    $userservice->getUser(123);

I get an object (not null), but $this->em in UserService is null, and as I already mentioned, constructor on UserService has never been called

One more thing, Controller and UserService are in different bundles (I really need that to keep project organized), but still: everyting else works fine, I can even call

$this->get('doctrine.orm.entity_manager')

in same controller that I use to get UserService and get valid (not null) EntityManager object.

Look like that I'm missing piece of configuration or some link between UserService and Doctrine config.

Gottlieb Notschnabel
  • 9,408
  • 18
  • 74
  • 116
Andrey Zavarin
  • 1,483
  • 2
  • 13
  • 12
  • Have you tried setter injection? It works? – gremo May 03 '12 at 07:56
  • If by 'setter injection' you mean add in setter method for EntityManager on my service and calling in controller with $this->get('doctrine.orm.entity_manager') as parameter, then yes, i've tried and it works. But i really like to use proper injection via config – Andrey Zavarin May 03 '12 at 08:00
  • 2
    I mean this: http://symfony.com/doc/current/book/service_container.html#optional-dependencies-setter-injection anyway `__constructor` is the error. – gremo May 03 '12 at 08:03
  • Um, than i haven't tried setter injection. __construct fixed the problem, but anyways, thank you for your help! – Andrey Zavarin May 03 '12 at 08:09

4 Answers4

112

Your class's constructor method should be called __construct(), not __constructor():

public function __construct(EntityManager $entityManager)
{
    $this->em = $entityManager;
}
richsage
  • 26,912
  • 8
  • 58
  • 65
  • 2
    Hi, in this example, how could I change the connection from default to any other? – ptmr.io Jul 27 '18 at 08:16
  • Right, but it would be even better if you used an interface. `public function __construct(EntityManagerInterface $entityManager)` – Hugues D Nov 09 '19 at 18:57
65

For modern reference, in Symfony 2.4+, you cannot name the arguments for the Constructor Injection method anymore. According to the documentation You would pass in:

services:
    test.common.userservice:
        class:  Test\CommonBundle\Services\UserService
        arguments: [ "@doctrine.orm.entity_manager" ]

And then they would be available in the order they were listed via the arguments (if there are more than 1).

public function __construct(EntityManager $entityManager) {
    $this->em = $entityManager;
}
Chadwick Meyer
  • 7,041
  • 7
  • 44
  • 65
18

Note as of Symfony 3.3 EntityManager is depreciated. Use EntityManagerInterface instead.

namespace AppBundle\Service;

use Doctrine\ORM\EntityManagerInterface;

class Someclass {
    protected $em;

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

    public function somefunction() {
        $em = $this->em;
        ...
    }
}
Robert Saylor
  • 1,279
  • 9
  • 11
  • 1
    Just in case anyone stumbles across this and is confused: the EntityManager has certainly not been depreciated. Using the interface helps with auto-wiring and is recommended but is by no means required. And the interface has been around for a long time. Nothing really new here. – Cerad Apr 20 '18 at 22:53
  • This is the answer. However, please do reference: https://stackoverflow.com/questions/22154558/symfony2-3-better-way-to-get-entitymanager-inside-a-controller – tfont Jul 11 '18 at 16:17
  • Update to my own solution. The proper way now should be to use Entities and Repositories. Entity Manager is already naturally injected into a repository. You can see an example here: https://youtu.be/AHVtOJDTx0M – Robert Saylor Oct 01 '18 at 14:26
7

Since 2017 and Symfony 3.3 you can register Repository as service, with all its advantages it has.

Check my post How to use Repository with Doctrine as Service in Symfony for more general description.


To your specific case, original code with tuning would look like this:

1. Use in your services or Controller

<?php

namespace Test\CommonBundle\Services;

use Doctrine\ORM\EntityManagerInterface;

class UserService
{
    private $userRepository;

    // use custom repository over direct use of EntityManager
    // see step 2
    public function __constructor(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUser($userId)
    {
        return $this->userRepository->find($userId);
    }
}

2. Create new custom repository

<?php

namespace Test\CommonBundle\Repository;

use Doctrine\ORM\EntityManagerInterface;

class UserRepository
{
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(UserEntity::class);
    }

    public function find($userId)
    {
        return  $this->repository->find($userId);
    }
}

3. Register services

# app/config/services.yml
services:
    _defaults:
        autowire: true

    Test\CommonBundle\:
       resource: ../../Test/CommonBundle
Tomas Votruba
  • 23,240
  • 9
  • 79
  • 115