1

How can I access EntityManager from a command in Symfony 3? It is supposed to be ContainerAware.

This is my code:

use Symfony\Component\Console\Command\Command;
class MyCommand extends Command
{
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $em = $this->getContainer()->getDoctrine();
        ...
    }
}

And I get this error:

Uncaught Symfony\Component\Debug\Exception\UndefinedMethodException: Attempted to call an undefined method named "getContainer" of class "AppBundle\Command\MyCommand"

It happens also if I extend from Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand (which was the symfony 2 way).

Also, injecting Doctrine\ORM\EntityManager in __construct() didn't work.

K. Weber
  • 2,643
  • 5
  • 45
  • 77
  • 1
    Forget about pulling it from the container. Figure out why injecting the entity manager "did not work". There are plenty of [examples](https://stackoverflow.com/questions/44809739/is-there-a-way-to-inject-entitymanager-into-a-service/44810136) on how to do it. – Cerad Apr 25 '19 at 11:50

3 Answers3

2

The best only clean way in 2019 is to use constructor injection. Anything else is being removed in Symfony 3.3/4+, so you only add yourself extra work in the future with $this->get().

Also, injecting Doctrine\ORM\EntityManager in __construct() didn't work

Try Doctrine\ORM\EntityManagerInterface type declaration in __construct().

Also make sure the command has autowire: true in the services.yaml config:

services:
    # in Symfony 3.3+
    _defaults:
        autowire: true

    App\:
        resource: ../src

    # in Symfony 2.8-3.3
    App\SomeCommand:
        autowire: true
Tomas Votruba
  • 23,240
  • 9
  • 79
  • 115
1

You cannot use getContainer because your command class is not aware of the container.

Make your command extend ContainerAwareCommand

So that you can use getContainer()

 use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;

Then extends ContainerAwareCommand :

class MyCommand extends ContainerAwareCommand

And then use it wherever you want :

$em     = $this->getContainer()->get('doctrine')->getManager('default');

EDIT thanks to @tomáš-votruba :

HOWEVER ContainerAware is deprecated in Symfony 4:

Using the EntityManager by injecting it :

So instead of forcefully getting the entity manager with the container, inject in your constructor instead and extend Command by using your command as a service:

namespace App\Command;

use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Console\Command\Command;

class MyCommand extends Command {

//add $entityManager attribute

private $entityManager;

public function __construct(ObjectManager $entityManager)
{
    $this->entityManager= $entityManager;

    // you *must* call the parent constructor
    parent::__construct();
}

As you can see in the constructor, we are injecting the entityManager with ObjectManager which is an interface whereas EntityManager is its ORM implementation, you can do it if you use the default services.yml or one that is set up for autowiring :

# config/services.yaml
services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: false       # Allows optimizing the container by removing unused services; this also means
                            # fetching services directly from the container via $container->get() won't work.
                            # The best practice is to be explicit about your dependencies anyway.
Dylan KAS
  • 4,840
  • 2
  • 15
  • 33
  • 6
    This is the worst you can do. Symfony is going away from this approach last 3 years. Use constructor injection – Tomas Votruba Apr 25 '19 at 12:16
  • 2
    Yep. What Tomas said. The ContainerAwareCommand class is depreciated in S4 and will probably go away completely in S5. Injection is your friend. – Cerad Apr 25 '19 at 12:19
  • @DylanKas Thanks for the update, I've noticed just now your comment :D – Tomas Votruba Jul 23 '19 at 14:31
0

I would suggest to not inherit from "ContainerAwareCommand" and use "extends Command" again. Generally you should define your command as a service and use dependency injection instead of use "get()" via the container. Just use __constructor injection. That's the way to go, also for commands.

This is how Symfony would suggest it:

https://symfony.com/doc/current/console/commands_as_services.html

Thomas Baier
  • 434
  • 3
  • 8
  • This right, but not clear. I prefer more specific response with example. See https://stackoverflow.com/a/55849164/1348344 – Tomas Votruba Apr 25 '19 at 12:20
  • 1
    Ok i understand. It was the first post and i will explain a lil more in the next ones! – Thomas Baier Apr 25 '19 at 12:25
  • 1
    Specific as "with code example". I know what you mean, because I already know the meaning of these words. But if I read your reply asking for this, it's difficult to connect the code with it. Also "Just use __constructor injection.", the author already did it "Also, injecting Doctrine\ORM\EntityManager in __construct() didn't work." – Tomas Votruba Apr 25 '19 at 12:26