Multiple databases with CakePHP - setting database

2019-04-15 07:48发布

My problem is identical to that described in this question - which is that I have a central database to host user login information while each user has their own transactional database which they will utilize for other operations besides login. There is no way of knowing which database the user will operate on until login is complete so it is not possible to use the database configuration file.

The solution provided with this question work perfectly except for one (major) problem. It doesn't seem to help with relationships on the model. In other words, I am able to set the database name in the Model immediately associated with my controller and it works fine but my models have many belongsTo and hasMany relationships and the dynamically set database name does not propagate to these related models.

I am using CakePHP 2.5.4

Car Controller Code

public function beforeFilter() {
    parent::beforeFilter();
    $dbName = $this->Auth->User('schema'); //accessing database name from session
    $this->Car->setDatabase($dbName); //setting dynamic database name in Model
    $this->set('cars', $this->Car->find('all));
}

App Model method

public function setDatabase($database) {
      $dbConfig  = ConnectionManager::getDataSource('default')->config;

      $dbConfig['database'] = $database;

      ConnectionManager::create($database, $dbConfig);
      $this->useDbConfig  = $database;
      $this->cacheQueries = false;
}

With the above code, the code perfectly queries Car table in the dynamically set database, but does not query any related models. All of those are blank.

To work around, I have had to make the following change in the controller code -

public function beforeFilter() {
    parent::beforeFilter();
    $dbName = $this->Auth->User('schema'); //accessing database name from session
    $this->Car->setDatabase($dbName); //setting dynamic database name in Model
    $this->Car->Dealer->setDatabase($dbName); //setting dynamic database in related models
    $this->Car->Dealer->Location->setDatabase($dbName); 
    $this->set('cars', $this->Car->find('all));
}

While this approach works - I feel there could be a cleaner way to tackle this. Any suggestions / thoughts are welcome.

Another approach I have been toying around with is setting a variable in all my models called dynamicDB. And if this is set to TRUE, then the model will use a different database. I tested this approach with the following code in my AppModel

public function __construct($id = false, $table = null, $ds = null) { 
    if ($this->dynamicDB) { 
        // Get saved company/database name 
        $this->dbName = 'otherDB'; 
        // Get common user-specific config (default settings in database.php) 
        $config = ConnectionManager::getDataSource('default')->config; 

        // Set correct database name 
        $config['database'] = $this->dbName; 
        // Add new config to registry 
        ConnectionManager::create($this->dbName, $config); 
        // Point model to new config 
        $this->useDbConfig = $this->dbName; 
    }

    parent::__construct($id, $table, $ds); 
}

This works perfect and would be ideal - but I don't know how to set the dynamic database name in my AppModel from controller. As you can see, I hardcoded the database name in the above piece of code just to test it out. The only solution I could think of is making the AppModel access my session variables directly but that would violate MVC pattern behavior. Any thoughts?

0条回答
登录 后发表回答