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?