2016-09-23 61 views
2

我的多租戶應用程序使用主數據庫,該主數據庫包含有關租戶(如名稱等)的信息以及每個租戶的應用程序特定數據庫symfony 2/3應用程序中的多個連接和實體管理器

我在內部config.yml教義部構成的主some_tenant連接和實體管理。

這讓我從一個控制器訪問主數據庫(例如,用於驗證和基於子域獲得租戶信息some_tenantsome_tenant.my-app.com)。而且它允許我在應用程序生命週期中使用特定於租戶的數據庫和實體管理器。

在我的配置教義部分看起來是這樣的:

doctrine: 
dbal: 
    default_connection: 'master' 
    connections: 
     master: 
      driver: pdo_mysql 
      host:  "%database_host%" 
      port:  "%database_port%" 
      dbname: "%database_name%" 
      user:  "%database_user%" 
      password: "%database_password%" 
      charset: UTF8 
     some_tenant: 
      driver: pdo_mysql 
      host:  "%database_host_some_tenant%" 
      port:  "%database_port_some_tenant%" 
      dbname: "%database_name_some_tenant%" 
      user:  "%database_user_some_tenant%" 
      password: "%database_password_some_tenant%" 
      charset: UTF8 

orm: 
    auto_generate_proxy_classes: "%kernel.debug%" 
    entity_managers: 
     master: 
      connection: master 
      mappings: 
       BEMultiTenancyBundle: ~ 
     some_tenant: 
      connection: some_tenant 
      mappings: 
       AppBundle: ~ 

來了一部分,我很不滿意,並不能找到一個解決方案:

首先,租客會超過20個。它開始變得混亂,這樣改變了原理配置。 然後是另一個配置文件,稱爲tenants.yml保持更像啓用/禁用應用程式功能的信息,租戶特定的主題等

該文件被加載,使用Config Component驗證,和容器參數是設置,以便租戶配置可在應用範圍內使用。 我想將數據庫證書也存儲在該文件中。

  1. 我想創建基於該配置的連接和實體管理器。每個租戶一個,可在應用程序生命週期中使用。

  2. 我還需要在控制檯命令bin/console doctrine:schema:update --em=some_tenant上使用它們來更新每個租戶的數據庫schem和bin/console doctrine:schema:update --em=master以更新master數據庫方案。

現在我想,要實現這一目標的唯一途徑是配置參數添加到理論部分編程後的appbundle被加載,並以前學說註冊表構造與給定的管理者和連接。

但我什至不能找到一個點,在那裏我可以實現這一點。

是否有另一種方法來到點1和2?

儘管有一個similiar question,我不確定它是否完全是大約相同的問題,並且是3歲左右,但我想用更多的解釋來發表這個問題。

+0

每個租戶數據庫是否具有相同的模式和實體? – Cerad

+0

是的。並且架構和映射在\ AppBundle \ Entity名稱空間中定義。 –

+0

一個選擇是製作一個控制檯命令,它將根據tenants.yml生成您的doctrine.yml配置文件。這至少會消除一些添加新租戶的手動步驟。否則,我所能建議的只是查看Doctrine Bridge中的RegisterMappingsPass,看看你是否可以做類似的事情。 – Cerad

回答

1

評論中的解決方案是一種簡單易行的解決方案,它可以工作。我遇到的另一個解決方案是使用一些外部條件動態替換租戶數據庫credentails,即請求HOST

您可以通過某種方式修改或擴展連接工廠,使其具有可用的請求堆棧(或爲其他SAPI提供ENV或控制檯參數的域),您可以擁有相同的實體管理器(即使default! )按需配置。

上簡單的介紹一下這個看起來像

use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;  
use Doctrine\Common\EventManager; 
use Doctrine\DBAL\Configuration; 
use Symfony\Component\HttpFoundation\RequestStack; 

class DynamicConnectionFactory extends Factory 
{ 
    /** @var RequestStack */ 
    private $requestStack; 

    public function __construct(array $types, RequestStack $stack) 
    { 
     parent::__construct($types); 
     $this->requestStack = $stack; 
    } 

    public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = array()) 
    { 
     $host = $this->requestStack->getMasterRequest()->getHost(); 
     $params = $this->replaceParamsForHost(array $params, $host); 
     return parent::createConnection($params, $config, $eventManager, $mappingTypes); 
    } 

    private function replaceParamsForHost(array $params, $host) 
    { 
     //do your magic, i.e parse config or call Memcache service or count the stars 
     return array_replace($params, ['database' => $host]); 
    } 
} 
+0

謝謝你這個苗條的解決方案。採用這種動態方法(只使用一個配置的連接並用當前需要的連接替換當前的連接),我將不得不擴展現有的教義:schema:update命令,以便爲每個租戶維護不同的db方案。因此,我選擇了Cerad的方式,並使用基於租戶配置的控制檯命令創建了原理配置,該配置完美無缺。 –

+0

如果你的模式是非常不同的,配置是唯一的方法 – ScayTrase

0

我認爲,要在symfony 2/3管理多租戶。 我們可以配置auto_mapping: false爲ORM的學說。 文件:config.yml

doctrine: 
    dbal: 
     default_connection: master 
     connections: 
      master: 
       driver: pdo_mysql 
       host:  '%master_database_host%' 
       port:  '%master_database_port%' 
       dbname: '%master_database_name%' 
       user:  '%master_database_user%' 
       password: '%master_database_password%' 
       charset: UTF8 
      tenant: 
       driver: pdo_mysql 
       host:  '%tenant_database_host%' 
       port:  '%tenant_database_port%' 
       dbname: '%tenant_database_name%' 
       user:  '%tenant_database_user%' 
       password: '%tenant_database_password%' 
       charset: UTF8 

    orm: 
     default_entity_manager: master 
     auto_generate_proxy_classes: "%kernel.debug%" 
     entity_managers: 
      master: 
       connection: master 
       auto_mapping: false 
       mappings: 
        AppBundle: 
         type: yml 
         dir: Resources/master/config/doctrine 
      tenant: 
       connection: tenant 
       auto_mapping: false 
       mappings: 
        AppBundle: 
         type: yml 
         dir: Resources/tenant/config/doctrine 

之後,我們無法處理通過覆蓋連接信息中request_listener喜歡的文章每個租戶的連接:http://mohdhallal.github.io/blog/2014/09/12/handling-multiple-entity-managers-in-doctrine-the-smart-way/ 我希望,這一做法能幫助別人與多租戶

工作

Regards, Vuong Nguyen

相關問題