12

I've been trying to call Entity Manager in a constructor:

function __construct()
{
    $this->getDoctrine()->getEntityManager();
    ...

but, as I've seen in this answer: Stackoverflow question, it can't be done.

So I wonder if there is a way to achieve it, as I have to call it often, and want to do some stuff in the constructor after getting the repository.

Edit:

I've tried with @MKhalidJunaid answer:

//src/MSD/HomeBundle/Resources/config/services.yml
services:
  imageTransController.custom.service:
    class:  MSD\HomeBundle\Controller\ImageTransController
    arguments: 
        EntityManager: "@doctrine.orm.entity_manager"

-

//app/config/config.php
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: doctrine_extensions.yml }
- { resource: "@MSDHomeBundle/Resources/config/services.yml" }

-

//src/MSD/HomeBundle/Controller/ImageTransController.php
namespace MSD\HomeBundle\Controller;

use Doctrine\ORM\EntityManager;
use MSD\HomeBundle\Entity\Imagen as Imagen;
use MSD\HomeBundle\Controller\HomeController as HomeController;


class ImageTransController extends HomeController
{
    protected $em ;

    function __construct(EntityManager $entityManager)
    {
    ...

but I'm getting this error:

Catchable Fatal Error: Catchable Fatal Error: Argument 1 passed to MSD\HomeBundle\Controller\ImageTransController::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in /home/manolo/MiServer/itransformer/app/cache/dev/jms_diextra/controller_injectors/MSDHomeBundleControllerImageTransController.php on line 13 and defined in /home/manolo/MiServer/itransformer/src/MSD/HomeBundle/Controller/ImageTransController.php line 38 (500 Internal Server Error)

New attempt:

I've also tried with @praxmatig answer:

//services.yml
parameters:
 msd.controller.imagetrans.class: MSD\HomeBundle\Controller\ImageTransController

services:
  msd.imagetrans.controller:
    class:  "%msd.controller.imagetrans.class%"
    arguments: [ @doctrine.orm.entity_manager  ]

-

//ImageTransController.php
namespace MSD\HomeBundle\Controller;

 use Doctrine\ORM\EntityManager;

class ImageTransController 
 {
    protected $em ;

    function __construct(EntityManager $em)
    {
        $this->em = $em;
    }
     ...

-

//routing.yml
msd_home_cambiardimensiones:
    pattern: /cambiardimensiones
    defaults: { _controller: MSDHomeBundle:msd.imagetrans.controller:cambiardimensionesAction }

but I get this error:

 Unable to find controller "MSDHomeBundle:msd.imagetrans.controller" - class "MSD\HomeBundle\Controller\msd.imagetrans.controllerController" does not exist. (500 Internal Server Error)
Community
  • 1
  • 1
Manolo
  • 24,020
  • 20
  • 85
  • 130
  • @MKhalidJunaid - If `EntityManager` is injected after the constructor, how could I pass `EntityManager` as a parameter in the constructor? Could you post a detailed answer? – Manolo Dec 14 '13 at 19:38
  • This is what dependency injection is for it is injected after constructor call to access the entity manager in constructor you need to make a service and pass it as argument see my answer below it will give you an idea – M Khalid Junaid Dec 14 '13 at 19:51

6 Answers6

13

You need to make a service for your class and pass the doctrine entity manager as the argument doctrine.orm.entity_manager.Like in services.yml

services:
  test.cutom.service:
    class:  Test\YourBundleName\Yourfoldernameinbundle\Test
    #arguments:
    arguments: [ @doctrine.orm.entity_manager  ] 
        #entityManager: "@doctrine.orm.entity_manager"

You must import your services.yml in config.yml

imports:
    - { resource: "@TestYourBundleName/Resources/config/services.yml" }

Then in your class's constructor get entity manager as argument

use Doctrine\ORM\EntityManager;
Class Test {

  protected $em;

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

Hope this makes sense

M Khalid Junaid
  • 63,861
  • 10
  • 90
  • 118
  • 1
    Yes, it does. Let me try tomorrow before mark as answered. Thank you for tour detailed answer. – Manolo Dec 14 '13 at 19:53
  • Well, if I do like you say I get this error: `Catchable Fatal Error: Argument 1 passed to MSD\HomeBundle\Controller\ImageTransController::__construct() must be an instance of MSD\HomeBundle\Controller\EntityManager, none given, called in /home/xxxx/webDir/itransformer/app/cache/dev/jms_diextra/controller_injectors/MSDHomeBundleControllerImageTransController.php on line 13 and defined in /home/xxxx/webDir/itransformer/src/MSD/HomeBundle/Controller/ImageTransController.php line 37 (500 Internal Server Error)`. Any idea of what is left to do? – Manolo Dec 15 '13 at 14:02
  • 1
    Have you properly imported your service in config.yml – M Khalid Junaid Dec 15 '13 at 14:19
  • Yes, like you said: `{ resource: "@MSDHomeBundle/Resources/config/services.yml" }`. If I change a word I'm getting an error, so I guess it is right. The problem seems to come from `services.yml`: `services: imagetrans.custom.service: class: MSD\HomeBundle\Controller\ImageTransController arguments: entityManager: "@doctrine.orm.entity_manager"` – Manolo Dec 15 '13 at 14:33
  • I've edited my question. Maybe you could find the typo. – Manolo Dec 15 '13 at 15:14
  • Sorry one thing i missed to add ,`use Doctrine\ORM\EntityManager;` in the top of your class – M Khalid Junaid Dec 15 '13 at 17:42
  • Now I get this error: `Catchable Fatal Error: Argument 1 passed to MSD\HomeBundle\Controller\ImageTransController::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, ...` – Manolo Dec 15 '13 at 19:05
  • @ManoloSalsas see my edited answer `arguments: [ @doctrine.orm.entity_manager ]` if this helps – M Khalid Junaid Dec 15 '13 at 19:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/43217/discussion-between-manolo-salsas-and-m-khalid-junaid) – Manolo Dec 15 '13 at 19:19
  • You might want to import the interface an entity manager shall implement to make you constructor more reusable: `use Doctrine\Common\Persistence\ObjectManager` ... `public function __construct(ObjectManager $entityManager)` – Th. Ma. Dec 19 '13 at 13:01
  • Just remove the typehinting and var_dump the variable, check what kind of object you're getting. – Steffen Brem Dec 20 '13 at 08:29
  • I've finally decided not to use EM in this way. Anyway, your answer is the original right one, but the bounty was for the one who solve the issue. Thank you anyway. – Manolo Dec 23 '13 at 19:54
5

Don't extend the base controller class when you register controller as a service. There is a documentation about it here

class ImageTestController
{
     private $em;

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

     public function someAction()
     {
         // do something with $this->em
     }
}

// services.yml
services:
    acme.controller.image_test:
        class: Acme\SomeBundle\Controller\ImageTestController

// routing.yml
acme:
    path: /
    defaults: { _controller: acme.controller.image_test:someAction }
praxmatig
  • 263
  • 3
  • 10
  • @ManoloSalsas replace `defaults: { _controller: MSDHomeBundle:msd.imagetrans.controller:cambiardimensionesAction }` to `defaults: { _controller: msd.imagetrans.controller:cambiardimensionesAction }`. You shouldn't specify the bundle name if you want to use the controller as service. – praxmatig Dec 17 '13 at 02:45
  • Tho added here, I would suggest to avoid using the entity manager when possible. Either use the ObjectManager or the EntityManagerInterface. Object manager should be able to do the necessary flush and commits. If you want to select stuff, I'd recommend using a customer repository and pass that one along. http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html#custom-repositories Then you can pass this object along as constructor along with it. – Anyone Dec 23 '13 at 16:38
  • 1
    I've decided not to use EM in this way, but your answer gave me the typo. You're the winner :) But I'll mark as answered the before one, which has the original answer. – Manolo Dec 23 '13 at 19:52
1

Why do you want to grab the Doctrine 2 EntityManager in the constructor of a controller?

Why not simply do $em = $this->getDoctrine()->getManager(); (or $em = $this->getDoctrine()->getEntityManager(); in Symfony 2.0) in the action(s) you need it? This saves you from the overhead of initializing the EntityManager when you don't need it.

If you really do want to do this, there are clear instructions on How to define Controllers as Services. Basically it looks like this:

# src/MSD/HomeBundle/Controller/ImageTransController.php

namespace MSD\HomeBundle\Controller;

use Doctrine\ORM\EntityManager;

class ImageTransController
{
    private $em;

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

    public function indexAction()
    {
        // use $this->em
    }
}


# src/MSD/HomeBundle/Resources/config/services.yml

parameters:
    msd.controller.image_trans.class: MSD\HomeBundle\Controller\ImageTransController

services:
    msd.controller.image_trans:
        class:     "%msd.controller.image_trans.class%"
        arguments: ["@doctrine.orm.default_entity_manager"]

# app/config/routing.yml

msd_home_cambiardimensiones:
    path:         /cambiardimensiones
    defaults:     { _controller: msd.controller.image_trans:indexAction }
Jasper N. Brouwer
  • 21,517
  • 4
  • 52
  • 76
0

You have to add

use Doctrine\ORM\EntityManager;

in your controller

Manolo
  • 24,020
  • 20
  • 85
  • 130
Amine
  • 271
  • 1
  • 6
0

I think you are in the right direction, I would take the second option:

For the second option I think that the definition inside routing.yml is wrong

//routing.yml 
msd_home_cambiardimensiones:
    pattern: /cambiardimensiones
    defaults: { _controller: msd.imagetrans.controller:cambiardimensionesAction }

Here just remove MSDHomeBundle from the _controller inside defaults

For the first option:

Does HomeController has its own constructor?

//src/MSD/HomeBundle/Resources/config/services.yml
services:
    imageTransController.custom.service:
        class:  MSD\HomeBundle\Controller\ImageTransController
        arguments: [@doctrine]

it could help then inside the constructor

__construct(Registry $doctrine)
$this->doctrine = $doctrine;

or

$this->em = $doctrine->getManager();
Kevin
  • 53,822
  • 15
  • 101
  • 132
felipep
  • 2,442
  • 1
  • 28
  • 35
0

I see that you are trying to get the entity manager in the constructor of the controller, which is not the way to do so , unless you plan to define your controller as a service. which on this case, you need to use dependency injection to inject the service entity manager.

But in general the common way to use entity manager in a controller is simply by getting it using the following code:

  $entityManager = $this->container->get('doctrine.orm.entity_manager');
shacharsol
  • 2,326
  • 20
  • 14