symfony - FOSUserBundle 的多实体管理器

标签 symfony doctrine-orm fosuserbundle

如果相当简单的话,在 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/

相关文章:

mysql - 如何在 Doctrine 中转义单引号

php - 多层次不同类型的继承

symfony - 使用 datafixtures 和 fosuserbundle 创建管理员用户

symfony - Docker Symfony 4和MySQL

php - 如何在 postRemove 事件期间获取实体的对象 ID?

doctrine-orm - 学说 2 : preFlush getScheduledEntityInsertions() works but not getScheduledEntityUpdates()

symfony - FOSUserBundle 无需密码注册

Symfony2 和 FOSUserBUndle - 强制用户更改密码

symfony - 扩展 Sylius 管理员用户时出现配置异常

php - 与 symfony 2.3 中的 Doctrine 的多重联系