I need to change yii2 active database in controller.
What I have so far:
Yii::$app->db = new yii\db\Connection([
'dsn' => 'dblib:host='.$company->host.';port=1433;dbname=Interface',
'username' => $company->db_user,
'password' => $company->db_password,
]);
Yii::$app->db->open();
$users = User::find()->all();
Can I change active database like that and then start using models in new database and how?
You can define multiple databases in the config file with both databases referring to different objects. Use the object with the respective database you want to use.
For example:
If you have two databases defined in the config file db and db1.
Then you can just use db1 instead of db wherever you need.
Related
I'm working on a project where I have to integrate with some tables form wordpress and other systems. To setup the database for my Laravel project I chose to use table a prefix and for my project tables it's working fine.
My problem is when I have to work with tables from other systems using Laravel. For example, the query below adds my project's table prefix to it:
$item = DB::table('cnp_item')
->where('code', $row[1])
->first();
Instead of querying the cnp_item table it's querying laravel_cnp_item table, which does not exist.
I know it makes sense since I configured a table prefix. My question is if there is anything I could do in some queries to make it ignore my table prefix.
Thanks for any help
You could define a different a different connection in config/database.php that omits the prefix setting:
'connections' => [
'mysql' => [
...
'prefix' => 'laravel',
...
], 'alternate' => [
...
'prefix' => '',
...
]
],
Then, if you want to query a table that doesn't have that connection, switch to it on the fly using DB::connection():
$item = DB::connection('alternate')->table('cnp_item')->where('code', $row[1])->first();
Or, if you use a Model, you should be able to define the connection and table, so you'd simply have to do:
class CNPItem extends Model {
protected $connection = 'alternate';
protected $table = 'cnp_items';
...
}
Then you'd simply query like so:
$item = CNPItem::where('code', $row[1])->first();
In the controller I want to change my default database connection, such that I can access a different database. It used to work, I created a function in the AppController, calling it in each controller when needed, containing the following:
ConnectionManager::config('database', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => $username,
'password' => $password,
'database' => $database,
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
]);
ConnectionManager::alias('database', 'default');
I created a new database connection, calling it 'database', and aliased default to this connection, such that instead of the default connection, this connection will be used. However, when I print
$this->{$modelName}->connection()->config();
It still gives the default connection. And an error saying the table doesn't exist, confirms I am not in the new connection's database.
Aliases are only picked up at table instantiation time
Alising connections on the fly generally works fine, but models / table classes only pick up connections up on their own once when they are being instantiated.
So if it doesn't work for a specific table, this is most probably because it has already been instantiated and picked up the default connection (the table registry only instantiates a table class once per alias).
So, either make sure that the tables are being instanted afterwards, which may require clearing (TableRegistry::clear()) / removing from (TableRegistry::remove()) the registry if the alias needs to be created late in the request cycle (which however could cause other problems, as you'd loose possibly applied dynamic configuration), or set the connection on the involved table(s) manually:
\Cake\Datasource\ConnectionManager::alias('database', 'default');
$connection = \Cake\Datasource\ConnectionManager::get('default');
$this->{$modelName}->setConnection($connection); // connection() before CakePHP 3.4
Apply connections dynamically in a more automated fashion
If you need this on multiple, or maybe all tables, or if you just want to shift away the responsibility from the controller (it most probably shouldn't be overly involved in configuring the model layer), then maybe dispatch an event when creating the alias, and use a base table class or a behavior that listens to the event, or maybe even use a "service" that knows about the tables and updates the tables connections accordingly.
\Cake\Datasource\ConnectionManager::alias('database', 'default');
$connection = \Cake\Datasource\ConnectionManager::get('default');
$event = new \Cake\Event\Event('Connection.aliased', $connection, ['source' => 'default']);
\Cake\Event\EventManager::instance()->dispatch($event);
For example in a table you could then do something like this, applying the new connection in case the table is configured to use the connection that has been aliased, ie if defaultConnectionName() === 'default', then pick up the new connection:
\Cake\Event\EventManager::instance()->on(
'Connection.aliased',
function (\Cake\Event\Event $event) {
// data() before CakePHP 3.4
if ($event->getData('source') === static::defaultConnectionName()) {
$this->setConnection($event->getSubject()); // subject() before CakePHP 3.4
}
}
);
See also
Cookbook > Events
Cookbook > Database Access & ORM > Behaviors
I built a sample project with dynamic connections based on the session variable.
I hope somebody find it useful:
https://github.com/jszoja/cakephp3-multidb
I documented it there.
This question already has answers here:
Laravel: connect to databases dynamically
(8 answers)
Closed 3 years ago.
I have the master database with login table and corresponding database settings for each user. On login I should dynamically change the db settings fetching from the table.
I can change the db connection but this is not persisting.
Config::set("database.connections.mysql", [
'driver' => 'mysql',
"host" => $usr_host,
"database" => $usr_database,
"username" => $usr_username,
"password" => $usr_password,
...
]);
edit:
New database is created for each user when he/she registers with the app and thus i dont have the database connection for each user defined in the config/database.php
This way you can set new parameter when it comes to database:
\Config::set('database.connections.mysql.database', $schemaName);
Remember about PURGE to persist this settings
DB::purge('mysql');
Cheers!
Well you can use the default database for user login and have a new field for the database name. Then whenever you need to query a different database, you can just change your db connection.
Something like this
$someModel = new SomeModel;
$databaseName = "mysql2"; // Dynamically get this value from db
$someModel->setConnection($databaseName);
$something = $someModel->find(1);
You can read more about it here.
http://fideloper.com/laravel-multiple-database-connections
you need to get the config first.. then alter the specific field then set it back..
$config = Config::get('database.connections.company');
$config['database'] = "company_tenant_$id";
$config['password'] = "test2123";
config()->set('database.connections.company', $config);
I think a good place to change the database connection place is in bootstrap/app.php file, use the code below:
$app->afterBootstrapping(\Illuminate\Foundation\Bootstrap\LoadConfiguration::class, function ($ap) {
// your database connection change may happens here
});
It is before ServiceProvider register and boot, so even if you use DB or Eloquent staff in ServiceProvider, it works very well.
In laravel what you can do is create the different connections in the connections array of the file conf/database, then these connections you can use them when you are going to carry out operations in your application.
If you use query builder or raw expresions you must use the connection ('name') method to perform queries, for example:
$users = DB::connection('mysql')
->table('users')
->select(...)
->get();
If you use eloquent you can specify the name of the connection in the model file in the connection attribute, for example:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The connection name for the model.
*
* #var string
*/
protected $connection = 'mysql';
}
A solution to your problem could be that you have created the different types of connections according to the users in the file conf/database, and save the name of the connection that the user uses as a column in the user table, and when you go to make the queries you get the name of the connection of the user, for example:
$user = User::find(Auth::id());
$connection = $user->connection;
$users = DB::connection($connection)
->table('users')
->select(...)
->get ();
more info:
https://laravel.com/docs/5.5/eloquent#eloquent-model-conventions
https://laravel.com/docs/5.5/database#read-and-write-connections
After an extensive search I found it this way:
Go to this file vendor\laravel\framework\src\Illuminate\Auth\Middleware\Authenticate.php
Go to the method: protected function authenticate($request, array $guards)
and right after the method has started, paste the following code:
if(auth()->check() && !empty( auth()->user()->db_name )){
$dynamic_db_name = auth()->user()->db_name;
$config = \Config::get('database.connections.mysql');
$config['database'] = $dynamic_db_name;
$config['password'] = "Your DB Password";
config()->set('database.connections.mysql', $config);
\DB::purge('mysql');
}
first we are checking if the user is logged in with
auth()->check()
Then as you may have added db_name name or the like column table to your users table according to each user. So in the next condition, I am making sure that the db_name is available:
&& !empty( auth()->user()->db_name )
Then after execution enters the if condition I get the db_name from the user record and set the configuration according to the user database, save the config and use purge method of DB class to persist this setting.
I was really stuck with it. I did not wanted to change my db connection in every class. So this is how I got it. Now I can use both Eloquent and DB without any tension anywhere. In my application I have one centeral database for login of all users and then for each organization there is a different database. So after the user has logged in, I do not need the centeral database (login database), I juse need the user/organization specific database. So this is how I got it to work.
I have an instanced web application that uses different databases for every instance but uses the same files.
What I want my application to do on boot:
Get database credentials from master instance table. This instance table is in the default 'mysql' connection that I have defined in app/config/database.php.
Connect to the instance database from that point on (I don't need the master instance database anymore)
I have tried to do this in my App:before() event, but that won't work as I don't have a sessions table in my master database. If I do it before the return array() in database.php it obviously can't connect because it doesn't have the correct master database credentials yet.
Where am I supposed to do this? Should I just disable sessions and do it in my App::before() and then enable sessions after?
Don't think its possible, But here is a possibility.
Read / Write Connections
Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Laravel makes this a breeze, and the proper connections will always be used whether you are using raw queries, the query builder, or the Eloquent ORM.
To see how read / write connections should be configured, let's look at this example:
'mysql' => array(
'read' => array(
'host' => '192.168.1.1',
),
'write' => array(
'host' => '196.168.1.2'
),
'driver' => 'mysql',
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Note that two keys have been added to the configuration array: read and write. Both of these keys have array values containing a single key: host. The rest of the database options for the read and write connections will be merged from the main mysql array. So, we only need to place items in the read and write arrays if we wish to override the values in the main array. So, in this case, 192.168.1.1 will be used as the "read" connection, while 192.168.1.2 will be used as the "write" connection. The database credentials, prefix, character set, and all other options in the main mysql array will be shared across both connections.
After some hours of experimenting and trying I have found out that the best option really is to create a PDO instance manually in the /app/config/database.php file and get the database credentials that way:
// Get instance row
if (!App::runningInConsole() && !array_key_exists('instance_found', $_ENV)) {
$conn = new PDO('mysql:dbname=instances;host=127.0.0.1', 'root', 'password');
$stmt = $conn->prepare('SELECT * FROM instances WHERE http_host=?');
$stmt->bindParam(1, $_SERVER['HTTP_HOST']);
$stmt->execute();
$instance = $stmt->fetch(PDO::FETCH_OBJ);
$conn = null;
if (!$instance) {
return Response::make('Whoops!', 404);
} else {
$_ENV['instance_found'] = true;
$database = $instance->mysql_database;
$username = $instance->mysql_username;
$password = $instance->mysql_password;
}
}
I'm rather new to Laravel 4. What I have is a bunch of sports statistics information and for organization purposes I have a database for every sport (NFL, MLB, etc...). What I want to do is change the DB easily in queries and mimic the functionality of $myslqi->select_db() but aside from setting up a bunch of database connections in the config file, I can't find a way to do what I'm looking for. It's all the same connection and same user, I just want to be able to switch the DB without having to insert a variable into SQL in order to point to the right database.
You will need to define the connections in the config/database like so:
'nba' => array(
'driver' => 'mysql',
...
),
'nfl' => array(
'driver' => 'mysql',
...
),
And then use these in models schema or queries
class NbaPlayers extends Eloquent {
protected $connection = 'nba';
//other stuff on your model
}
$nflplayers = DB::connection('nfl')->whatever
If you define the connection in the model, you will use model::all() or whatever without having to define the connection everytime