有没有办法将 EntityManager 注入服务
Is there a way to inject EntityManager into a service
在使用 Symfony 3.3
时,我声明了这样的服务:
class TheService implements ContainerAwareInterface
{
use ContainerAwareTrait;
...
}
在我需要 EntityManager 的每个操作中,我从容器中获取它:
$em = $this->container->get('doctrine.orm.entity_manager');
这有点烦人,所以我很好奇 Symfony 是否有类似 EntityManagerAwareInterface
.
的东西
有时我将 EM 注入到容器上的服务中,就像 services.yml 中这样:
application.the.service:
class: path\to\te\Service
arguments:
entityManager: '@doctrine.orm.entity_manager'
然后在服务 class 上通过 __construct 方法获取它。
希望对你有帮助。
传统上,您会在 services.yml
文件中创建一个新的服务定义,将 entity manager
作为构造函数的参数
app.the_service:
class: AppBundle\Services\TheService
arguments: ['@doctrine.orm.entity_manager']
最近,随着 Symfony 3.3 的发布,默认的 symfony-standard-edition 将它们的默认 services.yml
文件更改为默认使用 autowire
并添加所有 classes AppBundle
待服务。这消除了添加自定义服务的需要,并且在构造函数中使用类型提示将自动注入正确的服务。
您的服务 class 将如下所示:
use Doctrine\ORM\EntityManagerInterface;
class TheService
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
// ...
}
有关自动定义服务依赖性的详细信息,请参阅https://symfony.com/doc/current/service_container/autowiring.html
新的默认 services.yml
配置文件可在此处获得:https://github.com/symfony/symfony-standard/blob/3.3/app/config/services.yml
我运行遇到了同样的问题,并通过编辑迁移代码解决了它。
我换了
$this->addSql('ALTER TABLE user ADD COLUMN name VARCHAR(255) NOT NULL');
来自
$this->addSql('ALTER TABLE user ADD COLUMN name VARCHAR(255) NOT NULL DEFAULT "-"');
我不知道为什么 bin/console make:entity
在这些情况下不提示我们提供默认值。 Django 做到了,而且效果很好。
所以我想回答你的子问题:
This is a bit annoying, so I'm curious whether Symfony has something
that acts like EntityManagerAwareInterface.
而且我认为有一个解决方案(我自己使用)。
这个想法是你稍微改变你的内核,以便它检查所有实现 EntityManagerAwareInterface
的服务并为它们注入它。
您还可以添加一个 EntityManagerAwareTrait
来实现 $entityManager
属性 和 setEntityManager()
setter。之后唯一剩下的就是 implement/use 和 interface/trait 耦合,例如您为 Logger 所做的方式。
(您也可以通过编译器传递完成此操作)。
<?php
// src/Kernel.php
namespace App;
use App\Entity\EntityManagerAwareInterface;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use function array_key_exists;
class Kernel extends BaseKernel implements CompilerPassInterface
{
use MicroKernelTrait;
public function process(ContainerBuilder $container): void
{
$definitions = $container->getDefinitions();
foreach ($definitions as $definition) {
if (!$this->isAware($definition, EntityManagerAwareInterface::class)) {
continue;
}
$definition->addMethodCall('setEntityManager', [$container->getDefinition('doctrine.orm.default_entity_manager')]);
}
}
private function isAware(Definition $definition, string $awarenessClass): bool
{
$serviceClass = $definition->getClass();
if ($serviceClass === null) {
return false;
}
$implementedClasses = @class_implements($serviceClass, false);
if (empty($implementedClasses)) {
return false;
}
if (array_key_exists($awarenessClass, $implementedClasses)) {
return true;
}
return false;
}
}
界面:
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\EntityManagerInterface;
interface EntityManagerAwareInterface
{
public function setEntityManager(EntityManagerInterface $entityManager): void;
}
特质:
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\EntityManagerInterface;
trait EntityManagerAwareTrait
{
/** @var EntityManagerInterface */
protected $entityManager;
public function setEntityManager(EntityManagerInterface $entityManager): void
{
$this->entityManager = $entityManager;
}
}
现在您可以使用它了:
<?php
// src/SomeService.php
declare(strict_types=1);
namespace App;
use Exception;
use App\Entity\EntityManagerAwareInterface;
use App\Entity\Entity\EntityManagerAwareTrait;
use App\Entity\Entity\User;
class SomeService implements EntityManagerAwareInterface
{
use EntityManagerAwareTrait;
public function someMethod()
{
$users = $this->entityManager->getRepository(User::Class)->findAll();
// ...
}
}
在使用 Symfony 3.3
时,我声明了这样的服务:
class TheService implements ContainerAwareInterface
{
use ContainerAwareTrait;
...
}
在我需要 EntityManager 的每个操作中,我从容器中获取它:
$em = $this->container->get('doctrine.orm.entity_manager');
这有点烦人,所以我很好奇 Symfony 是否有类似 EntityManagerAwareInterface
.
有时我将 EM 注入到容器上的服务中,就像 services.yml 中这样:
application.the.service:
class: path\to\te\Service
arguments:
entityManager: '@doctrine.orm.entity_manager'
然后在服务 class 上通过 __construct 方法获取它。 希望对你有帮助。
传统上,您会在 services.yml
文件中创建一个新的服务定义,将 entity manager
作为构造函数的参数
app.the_service:
class: AppBundle\Services\TheService
arguments: ['@doctrine.orm.entity_manager']
最近,随着 Symfony 3.3 的发布,默认的 symfony-standard-edition 将它们的默认 services.yml
文件更改为默认使用 autowire
并添加所有 classes AppBundle
待服务。这消除了添加自定义服务的需要,并且在构造函数中使用类型提示将自动注入正确的服务。
您的服务 class 将如下所示:
use Doctrine\ORM\EntityManagerInterface;
class TheService
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
// ...
}
有关自动定义服务依赖性的详细信息,请参阅https://symfony.com/doc/current/service_container/autowiring.html
新的默认 services.yml
配置文件可在此处获得:https://github.com/symfony/symfony-standard/blob/3.3/app/config/services.yml
我运行遇到了同样的问题,并通过编辑迁移代码解决了它。
我换了
$this->addSql('ALTER TABLE user ADD COLUMN name VARCHAR(255) NOT NULL');
来自
$this->addSql('ALTER TABLE user ADD COLUMN name VARCHAR(255) NOT NULL DEFAULT "-"');
我不知道为什么 bin/console make:entity
在这些情况下不提示我们提供默认值。 Django 做到了,而且效果很好。
所以我想回答你的子问题:
This is a bit annoying, so I'm curious whether Symfony has something that acts like EntityManagerAwareInterface.
而且我认为有一个解决方案(我自己使用)。
这个想法是你稍微改变你的内核,以便它检查所有实现 EntityManagerAwareInterface
的服务并为它们注入它。
您还可以添加一个 EntityManagerAwareTrait
来实现 $entityManager
属性 和 setEntityManager()
setter。之后唯一剩下的就是 implement/use 和 interface/trait 耦合,例如您为 Logger 所做的方式。
(您也可以通过编译器传递完成此操作)。
<?php
// src/Kernel.php
namespace App;
use App\Entity\EntityManagerAwareInterface;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use function array_key_exists;
class Kernel extends BaseKernel implements CompilerPassInterface
{
use MicroKernelTrait;
public function process(ContainerBuilder $container): void
{
$definitions = $container->getDefinitions();
foreach ($definitions as $definition) {
if (!$this->isAware($definition, EntityManagerAwareInterface::class)) {
continue;
}
$definition->addMethodCall('setEntityManager', [$container->getDefinition('doctrine.orm.default_entity_manager')]);
}
}
private function isAware(Definition $definition, string $awarenessClass): bool
{
$serviceClass = $definition->getClass();
if ($serviceClass === null) {
return false;
}
$implementedClasses = @class_implements($serviceClass, false);
if (empty($implementedClasses)) {
return false;
}
if (array_key_exists($awarenessClass, $implementedClasses)) {
return true;
}
return false;
}
}
界面:
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\EntityManagerInterface;
interface EntityManagerAwareInterface
{
public function setEntityManager(EntityManagerInterface $entityManager): void;
}
特质:
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\EntityManagerInterface;
trait EntityManagerAwareTrait
{
/** @var EntityManagerInterface */
protected $entityManager;
public function setEntityManager(EntityManagerInterface $entityManager): void
{
$this->entityManager = $entityManager;
}
}
现在您可以使用它了:
<?php
// src/SomeService.php
declare(strict_types=1);
namespace App;
use Exception;
use App\Entity\EntityManagerAwareInterface;
use App\Entity\Entity\EntityManagerAwareTrait;
use App\Entity\Entity\User;
class SomeService implements EntityManagerAwareInterface
{
use EntityManagerAwareTrait;
public function someMethod()
{
$users = $this->entityManager->getRepository(User::Class)->findAll();
// ...
}
}