7

コア構成データベースがあり、各行は基本的な構成などを含む「アプリ」
です。アプリを選択したら、その行 (ID) のプロパティを使用してデータベースに接続したいと思います。ホストも変更される可能性があります。行に基づいています。

私が望むのは、Doctrine サービスが必要な場所にいる場合 (URI に基づいて知っています)、これらの詳細を使用して Doctrine サービスをセットアップするサービスを登録することです。

エンティティマネージャとさまざまなDoctrineリスナー/イベントサブを使用しています

ConnectionFactory をいじってみましたが、これがサブスクライバーに問題を引き起こしているようです。

Doctrine サービスを透過的に変更する何かを接続して、コントローラーが接続先の DB ホストと DB 名を知らなくても動作できるようにする最善の方法は何ですか?

このタイプの各 DB は同じ構造を持つため、すべてのエンティティ マッピングが正しくなります。

私は本当にクリーンな実装を探しています。サービス コンテナを使用して「ハッキング」を回避できることを願っています。

誰かがこれを行う知識を持っていますか?

4

5 に答える 5

11

これら 2 つの投稿を組み合わせることで、私自身の非常によく似た問題を解決することができました。これが私の解決策です。他の人にとっては役立つかもしれません:

<?php

namespace Calitarus\CollaborationBundle\EventListener;

use Symfony\Component\HttpFoundation\Request;
use Doctrine\DBAL\Connection;
use Exception;
use Monolog\Logger;



class DatabaseSwitcherEventListener {

    private $request;
    private $connection;
    private $logger;

    public function __construct(Request $request, Connection $connection, Logger $logger) {
        $this->request = $request;
        $this->connection = $connection;
        $this->logger = $logger;
    }


    public function onKernelRequest() {
        if ($this->request->attributes->has('_site')) {
            $site = $this->request->attributes->get('_site');

            $connection = $this->connection;
            $params     = $this->connection->getParams();

            $db_name = 'br_'.$this->request->attributes->get('_site');
            // TODO: validate that this site exists
            if ($db_name != $params['dbname']) {
                $this->logger->debug('switching connection from '.$params['dbname'].' to '.$db_name);
                $params['dbname'] = $db_name;
                if ($connection->isConnected()) {
                    $connection->close();
                }
                $connection->__construct(
                    $params, $connection->getDriver(), $connection->getConfiguration(),
                    $connection->getEventManager()
                );

                try {
                    $connection->connect();
                } catch (Exception $e) {
                    // log and handle exception
                }
            }
        }
    }
}

これを機能させるために、services.yml を次のように設定します。

services:
    cc.database_switcher:
        class:      Calitarus\CollaborationBundle\EventListener\DatabaseSwitcherEventListener
        arguments:  [@request, @doctrine.dbal.default_connection, @logger]
        scope:      request
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

そして、私の場合は URL の一部である _site パラメーターを取得するためのルーティング構成がありますが、セットアップに応じて他の方法で取得できる可能性があります。

resource: "@CCollabBundle/Controller"
type:     annotation
prefix:   /{_site}
defaults:
 _site: default
于 2014-07-05T10:09:04.493 に答える
10

これは、新しく改良された無反射バージョンです。

#services.yml
acme_app.dynamic_connection:
    class: %acme.dynamic_doctrine_connection.class%
    calls:
        - [setDoctrineConnection, [@doctrine.dbal.default_connection]]


<?php

namespace Acme\Bundle\AppBundle;

use Doctrine\DBAL\Connection;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
use Exception;

class DynamicDoctrineConnection
{
    /**
     * @var Connection
     */
    private $connection;

    /**
     * Sets the DB Name prefix to use when selecting the database to connect to
     *
     * @param  Connection       $connection
     * @return SiteDbConnection $this
     */
    public function setDoctrineConnection(Connection $connection)
    {
        $this->connection = $connection;

        return $this;
    }

    public function setUpAppConnection()
    {
        if ($this->request->attributes->has('appId')) {
            $connection = $this->connection;
            $params     = $this->connection->getParams();

            // we also check if the current connection needs to be closed based on various things
            // have left that part in for information here
            // $appId changed from that in the connection?
            // if ($connection->isConnected()) {
            //     $connection->close();
            // }

            // Set default DB connection using appId
            //$params['host']   = $someHost;
            $params['dbname'] = 'Acme_App'.$this->request->attributes->get('appId');

            // Set up the parameters for the parent
            $connection->__construct(
                $params, $connection->getDriver(), $connection->getConfiguration(),
                $connection->getEventManager()
            );

            try {
                $connection->connect();
            } catch (Exception $e) {
                // log and handle exception
            }
        }

        return $this;
    }
}
于 2013-02-27T11:23:19.703 に答える