#php #symfony #doctrine-orm #symfony-dependency-injection
#php #symfony #doctrine-orm #symfony-dependency-injection
Вопрос:
У меня есть проект, использующий небольшое количество компонентов Symfony, включая внедрение зависимостей. В основном для небольшого проекта командной строки. Вчера я провел рефакторинг, чтобы использовать внедрение зависимостей, и теперь я пытаюсь провести рефакторинг и включить Doctrine в микс.
До того, как я добавил DI, у меня был загрузочный файл, который настраивал doctrine и передавал EntityManager в соединении. Это не очень хорошая идея; вы можете понять, почему я хотел провести рефакторинг.
Итак, как мне настроить соединение Doctrine с DI? Сначала я предположил, что автоматическая проводка позаботится об этом автоматически. Это то, что у меня есть до сих пор. Внизу я добавлю пару вещей, которые я безуспешно пробовал, но которые приводят меня к другому сообщению об ошибке.
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:
SymfonyComponentConsoleCommandCommand:
tags: ['command']
App:
lazy: true
resource: '../src'
AppApplication:
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());
и когда я добавляю EntityManagerInterface к одной из команд, я получаю сообщение об ошибке:
class CreateRecipientCommand extends Command
{
protected $em;
public function __construct(EntityManagerInterface $entityManager, string $name = null)
{
$this->em = $entityManager;
parent::__construct($name);
}
}
Сообщение об ошибке:
Cannot autowire service "AppCommandCreateRecipientCommand": argument "$entityManager" of method "__construct()" references interface "DoctrineORMEntityManagerInterface" but no such service exists. Did you create a class that implements this interface?
Я знаю, что мне нужно где-то подключить Entity Manager и Doctrine factory, но я не могу понять, как это сделать.
До того, как я добавил DI, у меня был загрузочный файл, который настраивал соединение следующим образом, и я передал эту переменную $EntityManager:
$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);
Я видел, что некоторые люди подключались к сервису как к фабрике? Но, похоже, я не могу снова найти документацию.
Работа с фабрикой
Я добавил DatabaseFactory, возвращающий соединение EntityManager.
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
DoctrineORMEntityManager:
factory: ['AppDatabaseFactory', 'createManager']
Теперь это работает, но мне интересно, лучший ли это способ сделать это, есть ли фабрика доктрин, которую я могу вызвать и передать ей параметры для соединения?
Комментарии:
1. Вы на правильном пути, определив службу с помощью factory . По сути, оберните свой код создания entity manager в фабричный класс. Нужно решить множество мелких деталей, но завод поможет вам начать. Кстати, в вашей конфигурации autowire влияет только на код в каталоге src. В принципе, ничего не знает о коде поставщика.
2. Спасибо, определенно наставил меня на правильный путь, чтобы заставить его работать. Мне интересно, есть ли DoctrineFactory, который я могу вызвать и передать ему соединение, а не благодарить за создание своего собственного?
3. Нет. Я не могу придумать EntityManagerFactory. Вы можете взглянуть на расширение DoctrineBundle DI, чтобы увидеть всю канитель, через которую они проходят для создания своих служб doctrine. Это одна из причин, по которой использование фреймворка так распространено. Рад, что у вас все получилось.