I want to use doctrine ODM for my project and I had the idea to have a seperate database for each of my clients. I want to be able to manage clients at runtime, through my API. My question now is:
When I setup doctrine ODM I have to set my database settings in my parameters.yml but I want to be able to select the database at runtime. I will have one main database with all my fixture collections and client index to know which database to select, but the client specific stuff will then be in those client databases. Each Document class will still be linked to a collection like in the normal situation, but then in a different database.
Is there a way to select the database for a Document class at runtime?
So lets say I go to www.myproject.com/client1/item/list I will list every item in the dbclient1.Items collection, and if I go to www.myproject.com/client2/item/list I will list all items in the dbclient2.Items collection.
I hope I made clear what I want to reach here... I couldn't find anything about this, but I think it would be weird if I was the first person to have a question about this... There must have been people before me with the same idea right?
Is there a way to select the database for a Document class at runtime?
Yes, you could call $dm->getConfiguration()->setDefaultDb('some_db_name') each time you need to change database but this can lead to unexpected behaviour when write comes into play.
Based on my experience (and few years practice on multi-tenant apps) the most bulletproof way is to create separate instances of DocumentManager per each context. You can achieve that by having one DocumentManager configured normally with your parameters but never used directly - instead you need to have a class that will manage its instances, fe:
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()
);
}
}
Thanks to this approach documents from few databases will never be managed by one DocumentManager, you have one class responsible for meddling with ODM configuration and framework-approach preserved (event subscribers et al are same for each DocumentManager).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With