FOSUserBundle 的多实体管理器 [英] Multiple entity manager for FOSUserBundle

查看:24
本文介绍了FOSUserBundle 的多实体管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Symfony 中根据 URL 使用不同的实体管理器/连接,如果相当容易的话.使用以下路由配置

To use different Entity Manager / Connection based on URL in Symfony if fairly easy. With the following routing configuration

connection:
    pattern:  /a/{connection}
    defaults: { _controller: AcmeTestBundle:User:index }

以及来自以下食谱;

如何使用多个实体管理器和连接

我的控制器看起来像这样;

My controller would look something like this;

class UserController extends Controller
{
    public function indexAction($connection)
    {

        $products = $this->get('doctrine')
            ->getRepository('AcmeStoreBundle:Product', $connection)
            ->findAll()
        ;
        ..................

并且我将能够从不同的 em/connection/database 获取产品信息.

and I'll be able to fetch product information from different em/connection/database.

现在,如果我在路由中添加这样的东西;

Now, if I add something like this to my routing;

login:
    pattern:  /a/{connection}/login
    defaults: { _controller: FOSUserBundle:Security:login }

如何轻松地使 login 使用 connection 变量中定义的连接?

How can I easily make the login to use connection as defined in the connection variable?

此设置假设每个数据库都有自己的用户登录信息(fos_user 表).

This setup assume each database has their own user login information (the fos_user table).

更新路由信息

编辑 2:

虽然我还是 PHP/Symfony/Doctrine 的新手,所以如果我在这里完全错了,请原谅我.我尝试在 FOSUserBundleDoctrineUserManager 中手动设置连接.下面是类的构造函数

I'm still new with PHP/Symfony/Doctrine though, so please forgive me if I'm completely wrong here. I tried to manually set the connection at FOSUserBundleDoctrineUserManager. The following is the constructor of the class

//
use DoctrineCommonPersistenceObjectManager;
//

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();
}

在控制器中,我们可以使用以下方法将 em 更改为 'testing'

In a controller, we can use the following method to change the em to 'testing'

$em = $this->get('doctrine')->getManager('testing');
$repository = $this->get('doctrine')->getRepository($class, 'testing')

为此,我将代码更改为以下代码以使用 EntityManager 而不是 ObjectManager.

For that I changed the code to the following to use EntityManager instead of ObjectManager.

//
//use DoctrineCommonPersistenceObjectManager;
use DoctrineORMEntityManager;
//

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();
}

我的应用运行良好,没有错误.

My app works fine with no error.

从它与控制器的工作方式来看,我尝试通过向该行添加参数来更改连接,但它仍然使用默认连接.

From the way it works with the controller, I tried changing the connection by adding a parameter to this line then, but it's still using the default connection.

$this->repository = $om->getRepository($class, 'testing');

我还能在这里遗漏什么?

What else could I be missing here?

推荐答案

如您所见,FOSUserBundle 只能有一个 EntityManager.您可以从设置 orm.xml

As you can see, FOSUserBundle can have only one EntityManager. You can see it from the settings orm.xml

<service id="fos_user.entity_manager" factory-service="doctrine" factory-method="getManager" class="DoctrineORMEntityManager" public="false">
    <argument>%fos_user.model_manager_name%</argument>
</service>

参数 %fos_user.model_manager_name% 在设置中指定为 model_manager_name

Parameter %fos_user.model_manager_name% specified in settings as model_manager_name

fos_user:
    db_driver:            ~ # Required
    user_class:           ~ # Required
    firewall_name:        ~ # Required
    model_manager_name:   ~

因此在构造函数中引入了 EntityManager 的实例,它不接受 getRepository 中的第二个参数.因此,标准的 FOSUserBundle 只能用于一个数据库.

So into the constructor comes the instance of EntityManager, which does not accept the second parameter in the getRepository. Therefore, the standard FOSUserBundle can only work with one database.

但这不是故事的结束,这是 Symfony :)我们可以写出 UserManager,它可以使用不同的数据库连接.在设置中看到 fos_user.user_manager 是一个 fos_user.user_manager.default.我们在 orm.xml 中找到它

But this is not the end of story, it's Symfony :) We can write out UserManager, that can use different db connections. In the setting see that fos_user.user_manager is a fos_user.user_manager.default. We find it in orm.xml

<service id="fos_user.user_manager.default" class="FOSUserBundleDoctrineUserManager" 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.我为这两个数据库写了一个简单的例子(如果你需要更多的数据库,你可以为这个服务写你的工厂)

We can override this class to add an additional parameter that will determine what kind of connection you want to use. Further by ManagerFactory you can get the desired ObjectManager. I wrote simple example for the two databeses (if you need more databases you can write your factory for this service)

在 services.yml 中定义您的服务

define your services in services.yml

services:
    acme.user_manager.conn1:
        class: AcmeDemoBundleServiceUserManager
        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: AcmeDemoBundleServiceUserManager
        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

I'm sorry that the answer was so big. If something is not clear to the end, I put the code on github

这篇关于FOSUserBundle 的多实体管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆