user2902536
user2902536

Reputation: 13

Change default database in cakephp controller

Using CakePHP version : 2.3.1

I have a default database that I use for authorisation, and based on that, different databases for different clients (database names have client names in it).

I have many models with various relationships between them. I want to retrieve them using one call (which recursively retrieves all associated model data).

Scenario:

Databases

default :
clients 
[id, password, name]
[1, 'qwertycolemak', 'amazon']
[2, '5t4ck0verfl0w', 'ebay']

Non-default databases(next 2)

client_amazon
students[student_id, student_name]
course_students [student_id, course_id]
courses [course_id, course_name]

client_ebay
(same as client_amazon)

Now, suppose I get request for [id:2, password:'5t4ck0verfl0w'] I check default database (clients), check password, retrieve name, in this case ebay

Now , the database I want to access is 'client_ebay'

I have different configs in database.php corresponding to each client. I tried changing datasource by using

$this->student->setDatasource('client_ebay')
$this->course->setDatasource('client_ebay')
$this->course_student->setDatasource('client_ebay')

This works for individual CRUD calls to models(non-recursive).

But when I use a call (with recursion on) like

$this->student->findById(5)

datasource defaults to 'default', and I get an error :
Table students for model student was not found in datasource default

How do I change the default datasource for all models(not one by one) dynamically through the controller?

Upvotes: 1

Views: 4385

Answers (3)

Sergio
Sergio

Reputation: 2469

Example in controller, Change multi DB for DataSources in CakePHP 2.5.x

App::uses('AppController', 'Controller');

class DemoController extends AppController {

public $uses = array('AppModel', 'GVA21', 'GVA01', 'GVA14', 'GVA24' );
public function test_dbs(){
    $this->autoRender=false;
    // Load ConnectManager
    App::uses('ConnectionManager', 'Model');
    // DataSource ['default']
    $MDM = $this->GVA14->find('count');
    echo "MDM.GVA14\n<br>";
    debug($MDM);
    // Get DataSource Config DB ['default'] and ['SRL']
    $confDeafult = ConnectionManager::$config->default;
    $confSrl = ConnectionManager::$config->SRL;
    // Change DataSource ['SRL']
    ConnectionManager::drop('default');
    ConnectionManager::create('default',$confSrl);  //<== Is permanet change Find All models Down
    // $this->GVA01->setDataSource('SRL'); //<== Is temp change Find model
    echo "SRL.GVA14\n<br>";
    $SRL = $this->GVA14->find('count');
    debug($SRL);
    $SRL = $this->GVA01->find('count');
    echo "SRL.GVA01\n<br>";
    debug($SRL);
    $SRL = $this->GVA21->find('count');
    echo "SRL.GVA21\n<br>";
    debug($SRL);
    // Change to DataSource ['default']
    debug(ConnectionManager::drop('default'));
    ConnectionManager::create('default',$confDeafult); //<== Is permanet change Find All models Down
    //$this->GVA01->setDataSource('default'); //<== Is temp change Find model
    $MDM = $this->GVA01->find('count');
    echo "MDM.GVA01\n<br>";
    debug($MDM);
    $MDM = $this->GVA21->find('count');
    echo "MDM.GVA21\n<br>";
    debug($MDM);
    ////FIN
    exit('FIN');
}

Upvotes: 0

ndm
ndm

Reputation: 60463

The model layer executes all DB operations on the object returned from Model::getDataSource(), so overwriting that method in your AppModel class and setting the proper datasource in there when necessary might be an option.

Here's an (untested) example, this would set the datasource to whatever is configured in Model.globalSource if necessary (and in case a value is set at all). The value could be changed wherever it's possible to call Configure::write().

...

class AppModel extends Model
{
    ...

    public function getDataSource()
    {
        $source = Configure::read('Model.globalSource');
        if($source !== null && $source !== $this->useDbConfig)
        {
            $this->setDataSource($source);
        }

        return parent::getDataSource();
    }

    ...
}

In your controller you could then do something like

Configure::write('Model.globalSource', 'client_ebay');
$student = $this->Student->findById(5);

Upvotes: 2

vicocamacho
vicocamacho

Reputation: 178

Have you tried modifying the $useDbConfig attribute of the Model? For example:

$this->Student->useDbConfig = 'client_ebay';

Upvotes: 0

Related Questions