如果相当简单的话,在 Symfony 中根据 URL 使用不同的实体管理器/连接。具有以下路由配置
connection:
pattern: /a/{connection}
defaults: { _controller: AcmeTestBundle:User:index }
以及来自以下食谱;
How to work with Multiple Entity Managers and Connections
我的 Controller 看起来像这样;
class UserController extends Controller
{
public function indexAction($connection)
{
$products = $this->get('doctrine')
->getRepository('AcmeStoreBundle:Product', $connection)
->findAll()
;
..................
我将能够从不同的 em/连接/数据库获取产品信息。
现在,如果我将这样的内容添加到我的路由中;
login:
pattern: /a/{connection}/login
defaults: { _controller: FOSUserBundle:Security:login }
如何轻松地使登录使用连接变量中定义的连接?
此设置假设每个数据库都有自己的用户登录信息(fos_user 表)。
编辑:更新路由信息
编辑2:
不过,我对 PHP/Symfony/Doctrine 还很陌生,所以如果我完全错了,请原谅我。我尝试在FOS\UserBundle\Doctrine\UserManager处手动设置连接。以下是该类的构造函数
//
use Doctrine\Common\Persistence\ObjectManager;
//
public function __construct(EncoderFactoryInterface $encoderFactory, CanonicalizerInterface $usernameCanonicalizer, CanonicalizerInterface $emailCanonicalizer, ObjectManager $om, $class)
{
parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer);
$this->objectManager = $om;
$this->repository = $om->getRepository($class);
$metadata = $om->getClassMetadata($class);
$this->class = $metadata->getName();
}
在 Controller 中,我们可以使用以下方法将 em 更改为“testing”
$em = $this->get('doctrine')->getManager('testing');
$repository = $this->get('doctrine')->getRepository($class, 'testing')
为此,我将代码更改为以下内容以使用 EntityManager 而不是 ObjectManager。
//
//use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityManager;
//
public function __construct(EncoderFactoryInterface $encoderFactory, CanonicalizerInterface $usernameCanonicalizer, CanonicalizerInterface $emailCanonicalizer, EntityManager $om, $class)
{
parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer);
$this->objectManager = $om;
$this->repository = $om->getRepository($class);
$metadata = $om->getClassMetadata($class);
$this->class = $metadata->getName();
}
我的应用程序运行良好,没有错误。
从它与 Controller 的工作方式来看,我尝试通过向此行添加参数来更改连接,但它仍然使用默认连接。
$this->repository = $om->getRepository($class, 'testing');
这里我还可能缺少什么?
最佳答案
如您所见,FOSUserBundle 只能有一个 EntityManager。你可以从设置orm.xml
中看到它<service id="fos_user.entity_manager" factory-service="doctrine" factory-method="getManager" class="Doctrine\ORM\EntityManager" public="false">
<argument>%fos_user.model_manager_name%</argument>
</service>
参数 %fos_user.model_manager_name% 在设置中指定为 model_manager_name
fos_user:
db_driver: ~ # Required
user_class: ~ # Required
firewall_name: ~ # Required
model_manager_name: ~
因此,EntityManager 的实例进入构造函数,它不接受 getRepository 中的第二个参数。因此,标准的 FOSUserBundle 只能使用一个数据库。
<小时/>但这不是故事的结局,这是 Symfony :) 我们可以写出UserManager,它可以使用不同的数据库连接。在设置中看到 fos_user.user_manager 是 fos_user.user_manager.default。我们在orm.xml中找到它
<service id="fos_user.user_manager.default" class="FOS\UserBundle\Doctrine\UserManager" public="false">
<argument type="service" id="security.encoder_factory" />
<argument type="service" id="fos_user.util.username_canonicalizer" />
<argument type="service" id="fos_user.util.email_canonicalizer" />
<argument type="service" id="fos_user.entity_manager" />
<argument>%fos_user.model.user.class%</argument>
</service>
我们可以重写此类来添加一个附加参数,该参数将确定您要使用哪种连接。进一步通过ManagerFactory就可以得到想要的ObjectManager。我为两个数据库编写了简单的示例(如果您需要更多数据库,您可以为此服务编写工厂)
在 services.yml 中定义您的服务
services:
acme.user_manager.conn1:
class: Acme\DemoBundle\Service\UserManager
public: true
arguments:
- @security.encoder_factory
- @fos_user.util.username_canonicalizer
- @fos_user.util.email_canonicalizer
- @doctrine
- 'conn1_manager'
- %fos_user.model.user.class%
acme.user_manager.conn2:
class: Acme\DemoBundle\Service\UserManager
public: true
arguments:
- @security.encoder_factory
- @fos_user.util.username_canonicalizer
- @fos_user.util.email_canonicalizer
- @doctrine
- 'conn2_manager'
- %fos_user.model.user.class%
你的经理
/**
* Constructor.
*
* @param EncoderFactoryInterface $encoderFactory
* @param CanonicalizerInterface $usernameCanonicalizer
* @param CanonicalizerInterface $emailCanonicalizer
* @param RegistryInterface $doctrine
* @param string $connName
* @param string $class
*/
public function __construct(EncoderFactoryInterface $encoderFactory, CanonicalizerInterface $usernameCanonicalizer,
CanonicalizerInterface $emailCanonicalizer, RegistryInterface $doctrine, $connName, $class)
{
$om = $doctrine->getEntityManager($connName);
parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer, $om, $class);
}
/**
* Just for test
* @return EntityManager
*/
public function getOM()
{
return $this->objectManager;
}
和简单的测试
/**
* phpunit -c app/ src/Acme/DemoBundle/Tests/FOSUser/FOSUserMultiConnection.php
*/
class FOSUserMultiConnection extends WebTestCase
{
public function test1()
{
$client = static::createClient();
/** @var $user_manager_conn1 UserManager */
$user_manager_conn1 = $client->getContainer()->get('acme.user_manager.conn1');
/** @var $user_manager_conn2 UserManager */
$user_manager_conn2 = $client->getContainer()->get('acme.user_manager.conn2');
/** @var $om1 EntityManager */
$om1 = $user_manager_conn1->getOM();
/** @var $om2 EntityManager */
$om2 = $user_manager_conn2->getOM();
$this->assertNotEquals($om1->getConnection()->getDatabase(), $om2->getConnection()->getDatabase());
}
}
很抱歉,答案太大了。如果最后还有什么不清楚的,我把代码放在github上
关于symfony - FOSUserBundle 的多实体管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14475180/