有没有办法将 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();
           // ...
        }
    }