如何在Repository中获取指定名称的Doctrine Entity Manager?
解决Laravel + Laravel-Doctrine多数据库EntityManager获取问题
嘿,我之前在Laravel里用laravel-doctrine处理多数据库的时候也碰到过这个问题,其实不用依赖Symfony/ZF3的工厂,有几个更简洁的方案可以搞定:
方案1:类型转换+安全校验
ManagerRegistry::getManager()返回的ObjectManager是EntityManager的父接口,而laravel-doctrine的每个连接默认都是EntityManager实例,所以我们可以安全地强制转换,再加个校验避免意外:
use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityManager; use App\Entities\Random; class RandomRepository extends EntityRepository { public function __construct(ManagerRegistry $managerRegistry) { $objectManager = $managerRegistry->getManager('namedManager'); // 安全校验,确保拿到的是EntityManager if (!$objectManager instanceof EntityManager) { throw new \RuntimeException('指定的连接未返回EntityManager实例'); } $entityManager = $objectManager; parent::__construct($entityManager, $entityManager->getClassMetadata(Random::class)); } }
方案2:直接从Laravel容器获取命名EntityManager
laravel-doctrine会把每个命名的EntityManager注册到Laravel容器中,绑定格式为em.{连接名},比如你的命名连接是namedManager,容器键就是em.namedManager。我们可以直接从容器获取,更直接:
use Illuminate\Container\Container; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityManager; use App\Entities\Random; class RandomRepository extends EntityRepository { public function __construct(Container $container) { // 直接从容器获取命名EntityManager $entityManager = $container->make('em.namedManager'); parent::__construct($entityManager, $entityManager->getClassMetadata(Random::class)); } }
如果想更优雅地用类型提示,也可以这样(laravel-doctrine已经帮我们绑定了带后缀的接口实例):
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use App\Entities\Random; class RandomRepository extends EntityRepository { public function __construct(EntityManagerInterface $namedEntityManager) { parent::__construct($namedEntityManager, $namedEntityManager->getClassMetadata(Random::class)); } }
然后在AppServiceProvider里绑定(如果laravel-doctrine没自动绑定的话):
$this->app->bind(EntityManagerInterface::class . '.namedManager', function ($app) { return $app->make('em.namedManager'); });
方案3:封装自定义Repository基类
如果多个Repository都需要处理多连接,建议封装一个基类,减少重复代码:
use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityManager; abstract class MultiConnectionRepository extends EntityRepository { public function __construct(ManagerRegistry $managerRegistry, string $connectionName, string $entityClass) { $objectManager = $managerRegistry->getManager($connectionName); if (!$objectManager instanceof EntityManager) { throw new \RuntimeException("连接[$connectionName]未提供EntityManager实例"); } parent::__construct($objectManager, $objectManager->getClassMetadata($entityClass)); } } // 你的业务Repository继承这个基类 class RandomRepository extends MultiConnectionRepository { public function __construct(ManagerRegistry $managerRegistry) { parent::__construct($managerRegistry, 'namedManager', Random::class); } }
额外注意:确保多连接配置正确
不管用哪个方案,都要先确认config/doctrine.php里的多连接配置是正确的:
return [ 'managers' => [ 'default' => [ 'connection' => 'mysql', 'mappings' => [ // 默认连接的实体映射 ] ], 'namedManager' => [ 'connection' => 'another_database', // 对应config/database.php里的连接名 'mappings' => [ // 命名连接的实体映射 ] ] ] ];
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

