簡體   English   中英

動態數據庫連接symfony2

[英]Dynamic database connection symfony2

我的symfony2項目有一個主數據庫和許多子數據庫。 為每個用戶創建每個子數據庫,數據庫憑據存儲在主數據庫中。 當用戶登錄時,從主數據庫中獲取用戶特定的數據庫憑證,理想情況下應建立子數據庫連接。 我用谷歌搜索了同樣的東西,我遇到了許多解決方案,最后做了以下事情:

#config.yml

doctrine:
dbal:
    default_connection:       default
    connections:
        default:
            dbname:           maindb
            user:             root
            password:         null
            host:             localhost
        dynamic_conn:
            dbname:           ~
            user:             ~
            password:         ~
            host:             localhost
orm:
    default_entity_manager:   default
    entity_managers:
        default:
            connection:       default
            auto_mapping:     true
        dynamic_em:
            connection:       dynamic_conn
            auto_mapping:     true

我創建了一個連接到主數據庫的默認連接和一個子數據庫的空連接,同樣我創建了實體管理器。 然后我創建了默認事件監聽器並將以下代碼添加到'onKernelRequest':

public function onKernelRequest(GetResponseEvent $event) //works like preDispatch in Zend
{
    //code to get db credentials from master database and stored in varaiables
    ....
    $connection = $this->container->get(sprintf('doctrine.dbal.%s_connection', 'dynamic_conn'));
    $connection->close();

    $refConn = new \ReflectionObject($connection);
    $refParams = $refConn->getProperty('_params');
    $refParams->setAccessible('public'); //we have to change it for a moment

    $params = $refParams->getValue($connection);
    $params['dbname'] = $dbName;
    $params['user'] = $dbUser;
    $params['password'] = $dbPass;

    $refParams->setAccessible('private');
    $refParams->setValue($connection, $params);
    $this->container->get('doctrine')->resetEntityManager('dynamic_em');
    ....
}

上面的代碼設置子數據庫參數並重置dynamic_em實體管理器。

當我在某個控制器中執行以下操作時,它可以正常工作,如果從子數據庫中獲取數據。

$getblog= $em->getRepository('BloggerBlogBundle:Blog')->findById($id); //uses doctrine

但是,當我使用安全上下文時,如下面的代碼所示,我收到錯誤'NO DATABASE SELECTED'。

$securityContext = $this->container->get('security.context');
$loggedinUserid = $securityContext->getToken()->getUser()->getId();

如何動態設置數據庫連接並使用安全上下文?

更新: -

花了很多時間在試驗和錯誤上,並在谷歌搜索,我意識到security.context是在執行onKernelRequest之前設置的。 現在的問題是如何注入數據庫連接細節到security.context,並注入?

我們需要設置DBAL和安全上下文並創建安全令牌,我們可以操作數據庫連接詳細信息。

因此,正如以下鏈接中的人所述,我對我的代碼進行了更改,因為這正是我想要做的。 http://forum.symfony-project.org/viewtopic.php?t=37398&p=124413

這留給我以下代碼添加到我的項目:

#config.yml //remains unchanged, similar to above code

編譯器傳遞創建如下:

// src/Blogger/BlogBundle/BloggerBlogBundle.php
namespace Blogger\BlogBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;

use Blogger\BlogBundle\DependencyInjection\Compiler\CustomCompilerPass;

class BloggerBlogBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->addCompilerPass(new CustomCompilerPass());
    }
}

編譯器傳遞如下:

# src/Blogger/BlogBundle/DependencyInjection/Compiler/CustomCompilerPass.php

class CustomCompilerPassimplements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $connection_service = 'doctrine.dbal.dynamic_conn_connection';
        if ($container->hasDefinition($connection_service))
        {
            $def = $container->getDefinition($connection_service);
            $args = $def->getArguments();
            $args[0]['driverClass'] = 'Blogger\BlogBundle\UserDependentMySqlDriver';
            $args[0]['driverOptions'][] = array(new Reference('security.context'));
            $def->replaceArgument(0, $args[0]);
        }
   }
}

驅動程序類代碼如下:

# src/Blogger/BlogBundle/UserDependentMySqlDriver.php

use Doctrine\DBAL\Driver\PDOMySql\Driver;

class UserDependentMySqlDriver extends Driver
{    
    public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
    {
        $dbname = .....  //store database name in variable
        $params['dbname'] = $dbname;
        return parent::connect($params, $username, $password, array());
    }
}

上面的代碼被添加到我的項目中,我認為這是我的問題的實際工作。

但現在我收到以下錯誤:

ServiceCircularReferenceException:檢測到服務“security.context”的循環引用,路徑:“profiler_listener - > profiler - > security.context - > security.authentication.manager - > fos_user.user_provider.username_email - > fos_user.user_manager - > doctrine.orm。 dynamic_manager_entity_manager - > doctrine.dbal.dynamic_conn_connection“。

怎么樣,我可以讓我的代碼工作? 我打賭我在這里做錯了什么,我會感激任何提示和幫助。

在這里,您需要在自己的業務中自己實現自己的邏輯。

在“如何創建實體管理器”上查看Doctrine的文檔。

然后使用明確的API創建服務:

$this->get('em_factory')->getManager('name-of-my-client'); // returns an EntityManager

你不能使用默認的DoctrineBundle,它不能用於動態功能。

class EmFactory
{
    public function getManager($name)
    {
        // you can get those values:
        // - autoguess, based on name
        // - injection through constructor
        // - other database connection
        // just create constructor and inject what you need
        $params = array('username' => $name, 'password' => $name, ....);

        // get an EM up and running
        // see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html#obtaining-the-entitymanager

        return $em;
    }
}

並聲明為服務。

我想為您的原始問題提出不同的解決方案。您可以使用PhpFileLoader動態定義config.yml的參數。

  1. 將主數據庫連接參數提取到單獨的文件中:

     # src/Blogger/BlogBundle/Resources/config/parameters.yml parameters: main_db_name: maindb main_db_user: root main_db_password: null main_db_host: localhost 
  2. 創建新的PHP腳本(比如DynamicParametersLoader.php),它將在app容器中注入新參數。 我認為您不能在此腳本中使用您的symfony應用程序,但您可以從$ container變量中讀取主數據庫憑據。 如下:

     # src/Blogger/BlogBundle/DependecyInjection/DynamicParametersLoader.php <?php $mainDbName = $container->getParameter('main_db_name'); $mainDbUser = $container->getParameter('main_db_user'); $mainDbPassword = $container->getParameter('main_db_password'); $mainDbHost = $container->getParameter('main_db_host'); # whatever code to query your main database for dynamic DB credentials. You cannot use your symfony2 app services here, so it ought to be plain PHP. ... # creating new parameters in container $container->setParameter('dynamic_db_name', $dbName); $container->setParameter('dynamic_db_user', $dbUser); $container->setParameter('dynamic_db_password', $dbPass); 
  3. 現在你需要告訴Symfony你的腳本和新的parameters.yml文件:

     # config.yml imports: - { resource: parameters.yml } - { resource: ../../DependencyInjection/DynamicParametersLoader.php } 
  4. 在此步驟中,您可以在配置中自由使用注入的參數:

     # config.yml ... dynamic_conn: dbname: %dynamic_db_name% user: %dynamic_db_user% password: %dynamic_db_password% ... 

使用此處發布的事件監聽器有一個非常好的解決方案:

Symfony2,動態數據庫連接/ Doctrine服務的早期覆蓋

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM