views:

40

answers:

2

The result I'm trying to achieve involves having an application with a database with minimal tables that store data regarding users on the system, this database would be used to verify user's login details when they login to the application. What I want to be able to do is to dynamically connect to another database once the user has logged in, based on details stored about that user in the main database.

Basically I want each user on the system to have their own database, connect to that database once they login, and be able to use common db model classes (since each user's db will have the same tables as every other user's db).

Is this possible? And if so, how would I implement the dynamic db connection (let's say in the action that validates their login details).

Any help would be greatly appreciated.

+1  A: 

Sure its possible. The implementation would really depend on more specific requirements than what you have given but i would probably make some sort of Db_Manager class. that abstracts away all the details to keep the actions short and seet... then you might simply have an action like:

public function loginAction()
{
   $request = $this->getRequest();
   $user = $request->getParam('username');
   $pass = $request->getParam('password');

   $auth = new My_Auth_Adapter($user, $pass);
   $authResult = Zend_Auth::getInstance()->authenticate($auth);

   if($authResult->isValid()){
      My_Db_Manager::connectForUser($authResult->getIdentity());
   }
}

This way you can handle all the actual sorting of which db to use and propagate to your models within the manager class. It would also give you an easy central point to handle working with multiple DB's in one request cycle if that comes up.

prodigitalson
+1  A: 

The simplest answer is not to make a second connection, but just change the default schema after you determine the name that the given user needs.

For example, fetch the name of the secondary db for a given user:

$db = Zend_Db::factory(...options...);
$secondary_db = $db->query("SELECT secondary_db 
    FROM user_data WHERE user = ?", $userid)
   ->fetchOne();

Then run a query to change the schema. Note the USE statement does not support being a prepared statement, so you have to execute it using the driver API:

$db->getConnection()->query("use $secondary_db");

Now if you reference a table without qualifying its schema, you'll get the table instance in the secondary database. This includes any query you run via the Zend_Db adapter or Table classes, etc.

But the USE statement only works if your secondary databases reside on the same database instance as your primary database with the user details. And also this assumes you don't need to re-authenticate the user against the database because each user has different database-level credentials.

Bill Karwin
Thanks Bill, I have a couple of questions regarding this solution (bear with me, I'm no expert).1. Would I be perfectly fine in placing my USE query in the contructor method of an abstract class which extends Zend_Db_Table_Abstract right before I call the parent's constructor function, and then have all my models extend the abtract class?
machinemessiah
2. When you say "But the USE statement only works if your secondary databases reside on the same database instance as your primary database with the user details", can you clarify, I'm not entirely sure what you mean and whether I will be satisfying this condition.Thanks again!
machinemessiah
He means that you would have to be using the same server instance/dsn... for example all dbs would have to be available from the mysql server at `mysql://localhost` as opposed to `mysql://mysql.auth.local` and `mysql://mysql.userbase.local`
prodigitalson
@prodigitalson: Right, but I use the term "instance" because in theory you could have more than one MySQL instance running on a single physical server (though this is uncommon).
Bill Karwin
@machinemessiah: I wouldn't put the USE query in the abstract table class, I'd do it immediately after authenticating the user. Keep the information (which user) close to the action (USE that user's db).
Bill Karwin
Thanks to both of you, you've been enormously helpful!
machinemessiah