Reputation: 1074
I am working on some APIs that needs to connect to two separate database, containing similar tables but different data.
I have configurated the two datasources in my app.php
and app_local.php
, and both of them are reachable.
With a bit of research I have found that ConnectionManager::alias
should be what I need, so I came up with this:
// Fetching `energy` DB data
ConnectionManager::alias('energy', 'default');
$energy = $this->Users->find()->first();
debug($energy);
ConnectionManager::dropAlias('default');
// Fetching `default` (gas) DB data
$gas = $this->Users->find()->first();
debug($gas);
The problem is that if I run those those queries like this the debug gives the same data, meaning that the data from the energy
database is printed two times.
But:
energy
find it gives me the correct results from the energy database.gas
find it gives me the correct results from the gas database.It looks like only the first datasource is actually used.
What I'm doing wrong?
Upvotes: 0
Views: 665
Reputation: 60463
Once a table class has been instantiated, it will hold the connection instance that was assigned to it when it was instantiated (connection
option for \Cake\ORM\Table::__construct()
), respectively the one that was created when the table first tried to obtain the connection (\Cake\ORM\Table::getConnection()
).
So dropping the alias alone won't do anything, the next call on the table will use the connection instance that the table already holds, it will not attempt to obtain a connection again on its own.
Since you want the connection change to affect everything, you will have to clear the table registry after dropping the connection alias, and load the tables again, so that that they will be created again with the actual default
connection (if you wanted to affect only specific instance, you could've assigned a new connection instance via setConnection()
). To avoid running into the same problem with already created table instances when creating the alias, you should most probably also clear the registry after that.
Basic example:
ConnectionManager::alias('energy', 'default');
$this->getTableLocator()->clear();
// table instances created after this point will respect the alias
$this->Users = null;
$this->loadModel('Users');
$energy = $this->Users->find()->first();
ConnectionManager::dropAlias('default');
$this->getTableLocator()->clear();
// table instances created after this point will use the non-aliased connection
$this->Users = null;
$this->loadModel('Users');
$gas = $this->Users->find()->first();
As you can see, this not only requires loading the model/table again, but also to unset the instance on the property, as otherwise loadModel()
will not actually load the table again, but instead return the instance that is already set on the $this->Users
property.
I would suggest that you switch to obtaining your models via the table locator, even in your controller, that way you can skip this awkward unset stuff, and you reduce the risk of accidentally accessing old instances stored on properties like $this->Users
:
ConnectionManager::alias('energy', 'default');
$this->getTableLocator()->clear();
$energy = $this->getTableLocator()-get('Users')->find()->first();
ConnectionManager::dropAlias('default');
$this->getTableLocator()->clear();
$gas = $this->getTableLocator()-get('Users')->find()->first();
You should probably also consider centralizing this connection switching somewhere in a service.
Upvotes: 1