not sure whats going here as the db area of laravel is like black magic to me, but im working on a multi tenancy app and use two main connections: tenants and tenant
when i create a new tenant i need to set the tenant db config as needed (prefix etc) and reconnect to the db before running migrations (all done without artisan calling the migrator via the oic container).
problem i have just found is that setting the config and then calling DB::reconnect('tenant') doesnt seem to work?
but setting the config and then calling DB::purge('tenant'); DOES work.
ive had a look and i see no reason other than something caching somewhere the connection as i assume both methods should achieve the same end result.
What laravel version? How can I replicate this?
Im facing the same issue in Laravel 5.1 and 5.3 (havent try 5.2). This is the code that replicate this behaviour:
<?php
use \Illuminate\Support\Facades\Config;
use \Illuminate\Support\Facades\DB;
class DbReconnectTest extends TestCase
{
public function testDbReconnect()
{
Config::set('database.connections.mysql.database', 'tenant1');
DB::reconnect('mysql');
$connections = DB::getConnections();
$this->assertEquals('tenant1', $connections['mysql']->getDatabaseName(), 'Initial reconnect works since it the default');
Config::set('database.connections.mysql.database', 'tenant2');
DB::reconnect('mysql');
$connections = DB::getConnections();
$this->assertEquals('tenant2', $connections['mysql']->getDatabaseName(), 'The actual reconnect to another db fails');
DB::purge('mysql');
DB::reconnect('mysql');
$connections = DB::getConnections();
$this->assertEquals('tenant2', $connections['mysql']->getDatabaseName(), 'If purged, it works');
}
}
Output:
./vendor/bin/phpunit
PHPUnit 5.5.3 by Sebastian Bergmann and contributors.
F 1 / 1 (100%)
Time: 78 ms, Memory: 10.50MB
There was 1 failure:
1) DbReconnectTest::testDbReconnect
The actual reconnect to another db fails
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'tenant2'
+'tenant1'
/Users/user/Desktop/laravelapp/tests/DbReconnectTest.php:18
FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
I faced the same issue with Laravel version 5.3.31.
I had to use DB::purge() and then DB::connection() instead of DB::reconnect().
@jcalonso @sakibbuddy ...and for anyone else venturing into multi-tenancy/multi-database arrangements, this issue is still relevant in Laravel 5.7.* however it is not a bug.
What you are experiencing is the intended behavior as far as I can tell.
Neither of following methods remove connections from the connection cache here:
DB::connectionDB::reconnectDB::disconnectTherefore calling the likes of:
Config::set(
'database.connections.YOUR_CONNECTION.database',
'YOUR_DATABASE'
);
...will have no effect until you call:
DB::purge($name)
...which will clear the $connections property within Illuminate\Database\DatabaseManager for the specified connection.
Then and only then will subsequent calls to connection and reconnect methods will make their way into the makeConnection method which retrieves the config for the connection in the current application state (i.e. your modifications via Config::set will be recognized at this point).
FYI: $name argument is optional when calling DB::purge and if not specified will default to purging the default connection only which can be a gotcha if you are using multiple connections for the same or multiple drivers.
Notes:
Config::set before or after DB::purge($name), just so long as you set the value setting the connectionDB::connection or DB::reconnect will work, so long as you have purged and set your config variable Alternatives:
The alternative to setting config variables on the fly and additionally having to purge, connect or reconnect would be to extend the db singleton registered in the container in your AppServiceProvider or some other provider of your choosing:
class AppServiceProvider extends ServiceProvider
{
/* ... */
public function register()
{
$this->app['db']->extend('YOUR_CONNECTION', function ($config, $name) {
if ( $condition) {
$config['database'] = $database_name;
}
return $this->app['db.factory']->make($config, $name);
});
}
/* ... */
}
...there's some articles here and docs here on extending bindings.
Hope that helps...
Most helpful comment
@jcalonso @sakibbuddy ...and for anyone else venturing into multi-tenancy/multi-database arrangements, this issue is still relevant in Laravel
5.7.*however it is not a bug.What you are experiencing is the intended behavior as far as I can tell.
Neither of following methods remove connections from the connection cache here:
DB::connectionDB::reconnectDB::disconnectTherefore calling the likes of:
...will have no effect until you call:
DB::purge($name)...which will clear the
$connectionsproperty withinIlluminate\Database\DatabaseManagerfor the specified connection.Then and only then will subsequent calls to
connectionandreconnectmethods will make their way into themakeConnectionmethod which retrieves the config for the connection in the current application state (i.e. your modifications viaConfig::setwill be recognized at this point).FYI:
$nameargument is optional when callingDB::purgeand if not specified will default to purging the default connection only which can be a gotcha if you are using multiple connections for the same or multiple drivers.Notes:
Config::setbefore or afterDB::purge($name), just so long as you set the value setting the connectionDB::connectionorDB::reconnectwill work, so long as you have purged and set your config variableAlternatives:
The alternative to setting config variables on the fly and additionally having to purge, connect or reconnect would be to extend the
dbsingleton registered in the container in yourAppServiceProvideror some other provider of your choosing:...there's some articles here and docs here on extending bindings.
Hope that helps...