7

I want to pass the EntityManager instance into the constructor of my controller, using this code:

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Doctrine\ORM\EntityManager;

class UserController extends Controller
{

    public function __construct( EntityManager $entityManager )
    {
        // do some stuff with the entityManager
    }
}

I do the constructor injection by putting the parameters into the service.yml file:

parameters:
#    parameter_name: value

services:
#    service_name:
#        class: AppBundle\Directory\ClassName
#        arguments: ["@another_service_name", "plain_value", "%parameter_name%"]
    app.user_controller:
        class: AppBundle\Controller\UserController
        arguments: ['@doctrine.orm.entity_manager']

the service.yml is included in the config.yml and when I run

php bin/console debug:container app.user_controller

I get:

 Information for Service "app.user_controller"
 =============================================

 ------------------ ------------------------------------- 
  Option             Value                                
 ------------------ ------------------------------------- 
  Service ID         app.user_controller                  
  Class              AppBundle\Controller\UserController  
  Tags               -                                    
  Public             yes                                  
  Synthetic          no                                   
  Lazy               no                                   
  Shared             yes                                  
  Abstract           no                                   
  Autowired          no                                   
  Autowiring Types   -                                    
 ------------------ ------------------------------------- 

However, calling a route which is mapped to my controller, I get:

FatalThrowableError in UserController.php line 17: Type error: Argument 1 passed to AppBundle\Controller\UserController::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in /home/michel/Documents/Terminfinder/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 202

I cant figure out, why the EntityManager is not getting injected?

MaxiGui
  • 6,190
  • 4
  • 16
  • 33
ltsstar
  • 832
  • 1
  • 8
  • 24
  • 1
    Have you cleared the cache? – lxg Jan 21 '17 at 13:03
  • @lxg I cleared the cache using php bin/console cache:clear --env=dev and manually deleted var/cache/dev/* as well – ltsstar Jan 21 '17 at 13:08
  • 1
    Declaring controllers as services is not considered a good practices by fabpot himself: https://github.com/symfony/symfony-docs/issues/457 . I agree with this. – COil Jan 21 '17 at 13:55
  • 1
    @COil I see your point, but there is an official documentation article about how to use controllers as services. https://symfony.com/doc/current/controller/service.html – ltsstar Jan 21 '17 at 14:06
  • Yes and one can read: "They are used by some developers for very specific use cases, such as DDD (domain-driven design) and Hexagonal Architecture applications." – COil Jan 21 '17 at 14:08
  • but that /should/ be working with my setup. – ltsstar Jan 21 '17 at 14:19
  • 1
    You need to configure the route to use the controller as a service: https://symfony.com/doc/current/controller/service.html#referring-to-the-service And ignore the naysayers. Perfectly fine to define controllers as services. If you still have trouble then update the question with your route. – Cerad Jan 21 '17 at 14:37
  • thank you @Cerad! I missed that point somehow. – ltsstar Jan 21 '17 at 14:51
  • Possible duplicate of [How to call Entity Manager in a constructor?](https://stackoverflow.com/questions/20587354/how-to-call-entity-manager-in-a-constructor) – tfont Aug 08 '18 at 14:36

4 Answers4

5

When using the base classController.php the Container is usually auto-wired by the framework in theControllerResolver.

Basically you are trying to mix up how things actually work.

To solve your problem you basically have two solutions:

  1. Do no try to inject the dependency but fetch it directly from the Container from within your action/method.

public function listUsers(Request $request) { $em = $this->container->get('doctrine.orm.entity_manager'); }

  1. Create a controller manually but not extend the Controller base class; and set ip up as a service

To go a bit further on this point, some people will advise to do not use the default Controller provided by Symfony.

While I totally understand their point of view, I'm slightly more moderated on the subject.

The idea behind injecting only the required dependencies is to avoid and force people to have thin controller, which is a good thing.

However, with a little of auto-determination, using the existing shortcut is much simpler.

A Controller / Action is nothing more but the glue between your Views and your Domain/Models.

Prevent yourself from doing too much in your Controller using the ContainerAware facility.

A Controller can thrown away without generate business changes in your system.

Boris Guéry
  • 47,316
  • 8
  • 52
  • 87
  • Thanks for your answer! What confused me was the fact that you can't inherit from the Controller base class while having an additional route configured. I finally decided to write services that do my entire business logic, the use of the entityManager included, and use the controller classes just as glue component (but keep the inheritance from the controller base class). – ltsstar Jan 23 '17 at 12:59
  • Thanks, but may i know where did you get the `doctrine.orm.entity_manager` ? And if it need to config, how should i do it? – fudu Nov 17 '18 at 10:31
2

Since 2017 and Symfony 3.3+, there is native support for controllers as services.

You can keep your controller the way it is, since you're using constructor injection correctly.

Just modify your services.yml:

# app/config/services.yml

services:
    _defaults:
        autowire: true

    AppBundle\:
        resouces: ../../src/AppBundle

It will:

  • load all controllers and repositories as services
  • autowire contructor dependencies (in your case EntityManager)


Step further: repositories as services

Ther were many question on SO regarding Doctrine + repository + service + controller, so I've put down one general answer to a post. Definitelly check if you prefer constructor injection and services over static and service locators.

Tomas Votruba
  • 23,240
  • 9
  • 79
  • 115
-1

Did you use following pattern to call the controller AppBundle:Default:index? if yes that should be the problem. If you want to use controller as a service you have to use the pattern: app.controller_id:indexAction which uses the id of the service to load the controller.

Otherwise it will try to create an instance of the class without using the service container.

For more information see the symfony documentation about this topic https://symfony.com/doc/current/controller/service.html

-4

The entity manager is available in a controller without needing to inject it. All it takes is:

$em = $this->getDoctrine()->getManager();

geoB
  • 4,578
  • 5
  • 37
  • 70
  • 2
    Does not answer the question. Down voted accordingly. – Cerad Jan 21 '17 at 14:39
  • 2
    So an answer should address the question even when the question relates to an inappropriate means to achieve some desired result? Doing so would seem to reinforce bad practices. – geoB Jan 21 '17 at 15:15
  • 4
    Comments work well for "don't do that" sort of stuff. Or provide an answer and then add a warning. Or, if you really think it is a bad practice then provide some support for your position. But I think you may find it difficult to convince many developers that service locators are "good" and dependency injection is "bad". – Cerad Jan 21 '17 at 15:35
  • But in this case this controller extends the default Symfony controller. So why inject the EM as it is already made available by the base Symfony controller. – COil Jan 21 '17 at 20:54
  • @COil - Excellent question though it is not really applicable to this sort of forum. There are a number of articles and blog posts on the subject. DI of course has the usual advantages of documenting exactly which dependencies are being used. Easier to understand and test etc. The code in the question does show the controller being extended from the Symfony base controller however it does not need to be. In fact, if the developer tries to use any of the base helper functions then they will quickly discover the need to add setContainer to the service definition. – Cerad Jan 22 '17 at 00:23