Symfony Dependency Injector and Setting up Doctrine

785 Views Asked by At

I have a project using a small amount of Symfony components, including dependency injection. Mainly for a small command-line project. Yesterday, I refactored to use Dependency injection, and now I'm trying to refactor and bring Doctrine into the mix.

Before I added DI I had a bootstrap file that set up doctrine and passed the EntityManager in the connection. This is not a good idea; you can see why I wanted to refactor.

So, how do I set up a Doctrine connection with DI? I assumed at first that the auto wiring would take care of it automatically. This is what I have so far. At the bottom, I'll add a couple of things I've tried with no luck but gets me to a different error message.

Composer.json:

"doctrine/orm": "^2.7",
"symfony/event-dispatcher": "^5.1",
"symfony/dependency-injection": "^5.1",
"symfony/config": "^5.1",
"symfony/yaml": "^5.1",
"symfony/monolog-bundle": "^3.5",
"symfony/process": "^5.1"

Security.yml:

parameters:

services:
  _defaults:
    autowire: true
    autoconfigure: true

  _instanceof:
    Symfony\Component\Console\Command\Command:
      tags: ['command']

  App\:
    lazy: true
    resource: '../src'

  App\Application:
    public: true
    arguments:
      - !tagged command

Index.php:

$container = new ContainerBuilder();

$loader = new YamlFileLoader($container, new FileLocator());
$loader->load(__DIR__ . '/config/services.yml');

//require __DIR__ . '/config/bootstrap.php';

$container->compile();

exit($container->get(Application::class)->run());

and when I add EntityManagerInterface to one of the commands I get an error:

class CreateRecipientCommand extends Command
{
    protected $em;

    public function __construct(EntityManagerInterface $entityManager, string $name = null)
    {
        $this->em = $entityManager;
        parent::__construct($name);
    }
}

Error message:

 Cannot autowire service "App\Command\CreateRecipientCommand": argument "$entityManager" of method "__construct()" references interface "Doctrine\ORM\EntityManagerInterface" but no such service exists. Did you create a class that implements this interface?

I know I need to bring in the Entity Manager and Doctrine factory somewhere, but I can't work out how.

Before I added DI I had a bootstrap file that set up the connection like this and I passed that $entityManager variable around:

$paths = [dirname(__DIR__) . '/src/Entities'];

$config = Setup::createConfiguration($isDevmode);
$driver = new AnnotationDriver(new AnnotationReader(), $paths);
$connectionParams = [
    'dbname' => 'dbname',
    'user' => 'root',
    'password' => 'root',
    'port' => '3306',
    'host' => 'localhost',
    'driver' => 'pdo_mysql',
];

$config->setMetadataDriverImpl($driver);

$entityManager = EntityManager::create($connectionParams, $config);

I've seen that some people have made the connection within the service as a factory? But, I can't seem to find the documentation again.

Working with Factory

I've added a DatabaseFactory returning the EntityManager connection.

class DatabaseFactory
{
    public function createManager(ContainerInterface $container)
    {
        $isDevmode = $container->getParameter('doctrine.orm.devmode');

        $paths = [dirname(__DIR__) . '/src/Entities'];

        $config = Setup::createConfiguration($isDevmode);
        $driver = new AnnotationDriver(new AnnotationReader(), $paths);
        
        $connectionParams = [
            'dbname' => $container->getParameter('doctrine.orm.dbname'),
            'user' => $container->getParameter('doctrine.orm.user'),
            'password' => $container->getParameter('doctrine.orm.password'),
            'port' => $container->getParameter('doctrine.orm.port'),
            'host' => $container->getParameter('doctrine.orm.host'),
            'driver' => $container->getParameter('doctrine.orm.driver'),
        ];

        $config->setMetadataDriverImpl($driver);

        return EntityManager::create($connectionParams, $config);
    }
}

services.yaml

Doctrine\ORM\EntityManager:
    factory: ['App\DatabaseFactory', 'createManager']

This now works but I'm wondering if this is the best way to do it, is there a doctrine factory I can call and pass it parameters for the connection?

0

There are 0 best solutions below