Doctrine ODM 在运行时选择数据库

3
我想在我的项目中使用Doctrine ODM,并考虑为每个客户端设置单独的数据库。我希望能够通过我的API在运行时管理客户端。现在我的问题是:
当我设置Doctrine ODM时,我必须在parameters.yml中设置我的数据库设置,但我希望能够在运行时选择数据库。我将拥有一个主数据库,其中包含所有我的装置集合和客户端索引以了解要选择哪个数据库,但特定于客户端的内容将存储在这些客户端数据库中。每个文档类仍将与集合链接,就像在正常情况下一样,但是在不同的数据库中。
是否有办法在运行时为文档类选择数据库?
假设我转到www.myproject.com/client1/item/list 我将列出dbclient1.Items集合中的每个项,如果我转到www.myproject.com/client2/item/list,我将列出dbclient2.Items集合中的所有项。
我希望我已经清楚地阐述了我的要求...我找不到任何关于此的信息,但我认为如果我是第一个有这个问题的人会很奇怪...肯定有人在我之前曾经有过同样的想法对吧?
2个回答

2
有没有一种方法可以在运行时为Document类选择数据库?
是的,您可以每次需要更改数据库时调用 $dm->getConfiguration()->setDefaultDb('some_db_name') ,但这可能会导致写入操作时出现意外行为。
根据我的经验(以及对多租户应用程序进行几年实践),最可靠的方法是针对每个上下文创建单独的 DocumentManager 实例。 您可以通过正常配置一个 DocumentManager 并从未直接使用它来实现这一点 - 相反,您需要有一个管理其实例的类,例如:
use Doctrine\ODM\MongoDB\DocumentManager;

class DocumentManagerFactory
{
    /**
     * DocumentManager created by Symfony.
     * 
     * @var DocumentManager
     */
    private $defaultDocumentManager;

    /**
     * All DocumentManagers created by Factory so far.
     * 
     * @var DocumentManager[]
     */
    private $instances = array();

    public function __construct(DocumentManager $dm) 
    {
        $this->defaultDocumentManager = $dm;
    }

    public function createFor(Context $ctx)
    {
        $databaseName = $ctx->getDatabaseName();
        if (isset($this->instances[$databaseName])) {
            return $this->instances[$databaseName];
        }
        $configuration = clone $this->defaultDocumentManager->getConfiguration();
        $configuration->setDefaultDB($databaseName);
        return $this->instances[$databaseName] = DocumentManager::create(
            $this->defaultDocumentManager->getConnection(),
            $configuration,
            $this->defaultDocumentManager->getEventManager()
        );
    }
}

通过这种方法,来自几个数据库的文档将永远不会由一个DocumentManager管理,您只需要一个类负责干预ODM配置并保留框架方法(事件订阅者等对于每个DocumentManager都是相同的)。


谢谢!我一直在为“写入操作时出现意外行为”而苦苦挣扎。我需要稍微修改您的代码,可能是因为我的Doctrine配置,DocumentManager :: create的结果始终与默认的DocumentManagaer具有相同的databaseName。 - Seballot
所以我将其更改为$configuration = clone $this->defaultDocumentManager->getConfiguration(); $newDm = DocumentManager::create( $this->defaultDocumentManager->getConnection(), $configuration, $this->defaultDocumentManager->getEventManager() ); $newDm->getConfiguration()->setDefaultDB($databaseName); return $this->instances[$databaseName] = $newDm; - Seballot

0

我还需要根据域名(例如,seballot.mysite.com将使用seballot数据库)设置默认的databaseName。

我做了这个hack,虽然不太好看但是效果很好。我在DocumentManager构造函数中添加了这些行。

$dbName = isset($_SERVER["HTTP_HOST"]) ? explode('.', $_SERVER["HTTP_HOST"])[0] : 'default_database_of_my_root_website';
$this->config->setDefaultDB($dbName);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接