FOSUserBundle的多个实体管理器

Moh*_*ria 40 symfony doctrine-orm fosuserbundle

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

connection:
    pattern:  /a/{connection}
    defaults: { _controller: AcmeTestBundle:User:index }
Run Code Online (Sandbox Code Playgroud)

并从以下食谱;

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

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

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

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

我将能够从不同的em/connection /数据库中获取产品信息.

现在,如果我在路由中添加这样的内容;

login:
    pattern:  /a/{connection}/login
    defaults: { _controller: FOSUserBundle:Security:login }
Run Code Online (Sandbox Code Playgroud)

如何轻松地使登录使用连接变量中定义的连接

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

编辑:更新的路由信息

EDIT2:

我仍然是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();
}
Run Code Online (Sandbox Code Playgroud)

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

$em = $this->get('doctrine')->getManager('testing');
$repository = $this->get('doctrine')->getRepository($class, 'testing')
Run Code Online (Sandbox Code Playgroud)

为此,我将代码更改为以下代码以使用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();
}
Run Code Online (Sandbox Code Playgroud)

我的应用程序工作正常,没有错误.

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

$this->repository = $om->getRepository($class, 'testing');
Run Code Online (Sandbox Code Playgroud)

我还能在这里找到什么?

Ale*_* B. 12

如您所见,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>
Run Code Online (Sandbox Code Playgroud)

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

fos_user:
    db_driver:            ~ # Required
    user_class:           ~ # Required
    firewall_name:        ~ # Required
    model_manager_name:   ~
Run Code Online (Sandbox Code Playgroud)

因此进入构造函数的是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>
Run Code Online (Sandbox Code Playgroud)

我们可以覆盖此类以添加一个额外的参数,该参数将确定您要使用的连接类型.通过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%
Run Code Online (Sandbox Code Playgroud)

你的经理

/**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

和简单的测试

/**
 * 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

对不起,答案太大了.如果到底有什么不清楚,我把代码放在github上