Laravel: connect to databases dynamically - php

I'm creating an application in Laravel 5(.1) where it is needed to connect to different databases. The only problem is that it's not known which databases it has to connect to, so making use of the database.php in config is not possible. A controller is in charge of making a connection with dynamically given connection details.
How can I make a new connection to a database, including making use of the DB class? (Or is this possible)
Thanks in advance!

The simplest solution is to set your database config at runtime. Laravel might expect these settings to be loaded from the config/database.php file, but that doesn't mean you can't set or change them later on.
The config loaded from config/database.php is stored as database in Laravel config. Meaning, the connections array inside config/database.php is stored at database.connections.
So you can easily override/change these connections like this:
Config::set("database.connections.mysql", [
"host" => "...",
"database" => "...",
"username" => "...",
"password" => "..."
]);
From there on out, any Eloquent models that use this mysql connection will be using this new database connection config.
I'd recommend doing this in a Service Provider if possible.

I've stumbled upon the same problem.
You can actually change database settings in runtime and use them.
Use the config() function to set extra or overwrite existing connection settings.
config(['database.connections.mynewconnection' => {settings here}]);
Keep in mind that these settings are cached. So when you need to use the new settings, purge the DB cache for the connection you're gonna use.
DB::purge('mynewconnection');
You can also manipulate the default connection that is used. This can come in handy if you wish to use migrations over different connections and keep track of them with a migration table within the used connection. Or other cool stuff ofcourse...
DB::setDefaultConnection('mynewconnection');

You might need to use these:
use Illuminate\Support\Facades\Config;
use DB;
Set database configurations:
Config::set("database.connections.mysql_external", [
'driver' => 'mysql',
"host" => "localhost",
"database" => "db_name",
"username" => "root",
"password" => "root",
"port" => '8889',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
]);
Connect to database and do stuff:
$users = DB::connection('mysql_external')->select('Select id from users');
Disconnect database and reset config variables
DB::disconnect('mysql_external');
Config::set("database.connections.mysql_external", [
'driver' => 'mysql',
"host" => "localhost",
"database" => "",
"username" => "",
"password" => "",
"port" => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
]);

I ran into this problem too with a script that imports multiple MS Access DB files into MySQL and I was not satisfied with any of the solutions which suggested editing configuration at runtime. It was ugly and messy to dynamically create a new config for every single Access DB file that I wanted to import. After some playing, I manged to persuade Laravel to switch DBs on the existing connection like this:
$mysqlConn = DB::connection();
$mysqlConn->getPdo()->exec("USE $schemaName;");
$mysqlConn->setDatabaseName($schemaName);

//appServiceProvider.php
Connection::macro('useDatabase', function (string $databaseName) {
$this->getPdo()->exec("USE `$databaseName`;");
$this->setDatabaseName($databaseName);
});
//usage.
\DB::connection()->useDatabase($dbName);

Create a new database connection in your databse.php
'connections' => [
'new_db_connection' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE_NEW', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
'old_db_connection' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE_OLD', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
]
Create helper method
static function getDatabaseName()
{
// Apply your condition and return databse
if(url('/') === 'http://localhost:8001'){
return 'new_db_connection';
} else {
return 'old_db_connection';
}
}
Using query builder
$databaseName = Helper::getDatabaseName();
DB::connection($databaseName)
->table('your table name')
->select('*')
->get();
Using model
<?php
namespace App\Models;
use App\Helper;
use Illuminate\Database\Eloquent\Model;
class Test extends Model {
public function __construct()
{
// You can apply the below variable dynamically and model
// will use that new connection
$this->connection = Helper::getDatabaseName();
}
protected $table = "users";
}

// Without Using any Facades
config(['database.connections.mynewconnection' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE_OLD', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
]]);
// With Facades
// Use Illuminate\Support\Facades\Config;
Config::set('database.connections.mynewconnection', [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE_OLD', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
]);
Access the database using Query Builder
DB::connection('mynewconnection')->table(<table_name>)->get();

we can do it another way
class SomeModel extends Eloquent {
if(app::environment('local'))
{
protected $connection = 'mysql2';
}
now extend use SomeModel class instead of Model everywhere.
Reference : https://fideloper.com/laravel-multiple-database-connections

Related

How to dynamically create multiple database in laravel

I am creating Laravel 6.6 project,
my query is how to create new multiple databases in laravel and then how to handle it,
if I fetch data from the new database that I was recently created then how to register a new database in .env file dynamically?
I am doing this the following way.
I do have a dummy entry for my client connections in my config/database.php like this:
'clientDb' => [
'driver' => 'mysql',
'host' => env('DB_CLIENT_HOST', '127.0.0.1'),
'port' => env('DB_CLIENT_PORT', '3306'),
'database' => env('DB_CLIENT_DATABASE', 'some_default_client_name'),
'username' => env('DB_CLIENT_USERNAME', 'root'),
'password' => env('DB_CLIENT_PASSWORD', ''),
'unix_socket' => env('DB_CLIENT_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
'dump' => [],
],
So, all my client-related models are used with $connection = 'clientDb';, the others using the default connection.
When changing a client (so i need to switch the connection), i just set the new connection by calling:
Config::set('database.connections.clientDb', [
'database' => NEW_DATABASE_NAME,
// all the other params from config
]);
After that, i figured out to call DB::reconnect('clientDb'); to get the connection really running.
I hope, this will lead you to the right direction 😉
You should usage from database.php in config directory. for example I have another mysql database which is different from main db:
so I add this code to database.php and connections section:
'mysql_second_db' => [
'driver' => 'mysql',
'host' => env('DB_HOST_SECOND_DB', '127.0.0.1'),
'port' => env('DB_PORT_SECOND_DB', '3306'),
'database' => env('DB_DATABASE_SECOND_DB', 'forge'),
'username' => env('DB_USERNAME_SECOND_DB', 'forge'),
'password' => env('DB_PASSWORD_SECOND_DB', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
],
You can use that:
$names=['name1','name2'];
Schema::create('t1', function($table)
{
$table->increments('id');
});
To set env look at that: ENV

Connect multiple databases dynamically in laravel [duplicate]

This question already has answers here:
How to use multiple databases in Laravel
(7 answers)
Closed 2 years ago.
I'm building an application which requires connecting 2 database. first one is static and another one is dynamic.
config/database.php is like
'mysql' =>
array (
'driver' => 'mysql',
'host' => '127.0.0.1',
'port' => '3306',
'database' => 'blog',
'username' => 'root',
'password' => '',
'unix_socket' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => NULL,
),
'business2' =>
array (
'driver' => 'mysql',
'host' => '127.0.0.1',
'port' => '3306',
'database' => 'blog2',
'username' => 'root',
'password' => '',
'unix_socket' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => NULL,
),
and model code is like
Class TableNewData extends Model
{
protected $connection = 'business3';
protected $table = 'table2_data';
public function getData()
{
return $this->get()->toArray();
}
}
I am able to connect multiple databases if I give static connection details but I am unable to connect database if I give dynamic connection details like
$connection = Session::get()->connection;
or
$connection=$_SESSION('connection');
What is the best way to connect multiple databases dynamically without effecting performance of application?
I had the same problem as you. This blog can definitely help you out.
The Ultimate Guide for Laravel Multi Tenant with Multi Database
Here is how the config/database.php file looks like based on your situation. Since the second one is dynamic, there is no need to define the database.
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'blog'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', 'password'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => 'InnoDB',
],
'business' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => '',
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', 'password'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => 'InnoDB',
],
Basically, set up a database helper function which connects to the database at runtime and then calls it in the right middleware.I just put the helper file at database/utilities/helpers.php
function connect($hostname, $username, $password, $database)
{
// Erase the tenant connection, thus making Laravel get the default values all over again.
DB::purge('business');
// Make sure to use the database name we want to establish a connection.
Config::set('database.connections.tenant.host', $hostname);
Config::set('database.connections.tenant.database', $database);
Config::set('database.connections.tenant.username', $username);
Config::set('database.connections.tenant.password', $password);
// Rearrange the connection data
DB::reconnect('business');
// Ping the database. This will throw an exception in case the database does not exists.
Schema::connection('tenant')->getConnection()->reconnect();
}
Don't forget to tell the composer that the helper function can be used globally by adding those line into the composer.json file.
"autoload": {
"classmap": [
"database"
],
"files":[
"database/utilities/helpers.php"
],
"psr-4": {
"App\\": "app/"
}
},
You also want to have static and dynamic models that should be extended to define which database connections to use.
class StaticModel extends Model
{
protected $connection = 'mysql';
}
class DynamicModel extends Model
{
protected $connection = 'business';
}
In the middleware set up the dynamic database connection according to the database name.
connect(getenv('DB_HOST'), getenv('DB_USERNAME'), getenv('DB_PASSWORD'), getenv('DB_SYMBOL') . $databasename);
Thus, you can use the model as normal but it has the dynamic database connections
One way of changing the connection at runtime is to set the values via the config:
config(['database.connections.mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'my_database'),
'username' => env('DB_USERNAME', 'my_user'),
'password' => env('DB_PASSWORD', 'my_password'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
]]);
This can be applied in a middleware to dynamically switch between tenant databases, for example.
You can also specify a connection via the DB facade:
DB::connection('mysql_2')->select(...);

How to change database name before authentication in laravel 5.1

I have multiple database. I want to change db name based on the url dynamically. How can I set particular db before authentication.
I want to change database from authentication to through out the application.
For ex.
If url is like lara.local.com/comapny1
then it will select database company1
If url is like lara.local.com/company2
then it will select database company2
Based on the selected database authentication will be done and selected database will be used for that user.
Make entry for second database in config/database.php
'company1' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'database1'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'company2' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => 'database2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
By default your queries will use the mysql connection to change connection to 'company1'
DB::connection('company1')->select($query);
Additionally you can set database connection for Model
$someModel = new MyModel;
$someModel->setConnection('company1');
You can use the Request::is() to get URI from URL
if(Request::is('company1')){
//change database to company1
Config::set("database.connections.company1.database", 'company1');
}
elseif(Request::is('company2'){
Config::set("database.connections.company1.database", 'company2');
}
You can achieve this thing with below steps:
1 Define multiple connection into database.php for example:
'db1' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'db1_connection',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
2 Use connection based on conditional statement(You should move this code else)
//Check url that contains 'MYCODE'
if ('URL Contains' == 'MYCODE') {
DB::disconnect();
Config::set('database.default','db1');
DB::reconnect();
}
else {
DB::disconnect();
Config::set('database.default','db2');
DB::reconnect();
}
It should work for you, however I haven't tested it. Reference taken from answer by Marcin Nabialek
You can do this in AppServiceProvider's boot() like this
public function boot()
{
if($this->app['request']->getHost()=='test.com') {
Config::set('database.default','mysql');
}
else{
Config::set('database.default','mysql1');
}
}

Laravel 5.2 use two different database connections simultaneously (sqlsrv + mysql)

I would like to do something like this when i use a model
class DB extends Model {
Protected $table = "mssql_table";
}
DB::useConnection("mssql")->All();
As far as configuration goes i've found out that I can add it myself in app/config/database.php
And so I did.
So now i've got this in my connetions:
'mssql' => [
'driver' => 'sqlsrv',
'host' => env('DB_MSSQL_HOST', 'localhost'),
'port' => env('DB_MSSQL_PORT', '3306'),
'database' => env('DB_MSSQL_DATABASE', 'forge'),
'username' => env('DB_MSSQL_USERNAME', 'forge'),
'password' => env('DB_MSSQL_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
and this to my .env file
DB_MSSQL_HOST=
DB_MSSQL_PORT=
DB_MSSQL_DATABASE=
DB_MSSQL_USERNAME=
DB_MSSQL_PASSWORD=
But what is the next step? google didnt really help me that much, in laravel 4.* you could use db::connection(); but it dosent seem to work anymore
Any ideas?
First, you need to set-up one or more databases in your config (be sure to change values, I just pretty much copied and pasted):
'db1' => [
'driver' => 'sqlsrv',
'host' => env('DB_MSSQL_HOST', 'localhost'),
'port' => env('DB_MSSQL_PORT', '3306'),
'database' => env('DB_MSSQL_DATABASE', 'forge'),
'username' => env('DB_MSSQL_USERNAME', 'forge'),
'password' => env('DB_MSSQL_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
'db2' => [
'driver' => 'sqlsrv',
'host' => env('DB_MSSQL_HOST', 'localhost'),
'port' => env('DB_MSSQL_PORT', '3306'),
'database' => env('DB_MSSQL_DATABASE', 'forge'),
'username' => env('DB_MSSQL_USERNAME', 'forge'),
'password' => env('DB_MSSQL_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
Then of course, you're going to need to create some migration schema for the newly added database (you need tables, etc.):
Schema::connection('db2')->create('table_name', function($table)
{
$table->increments('id');
...
});
Now in your Eloquent model, you can define what database you want to use like so:
class ModelName extends Eloquent {
protected $connection = 'db2';
}
Thank you #Mike Barwick, the only thing that i was looking for was protected $connection = ""
Now i can query 2 databases at once

Using multiple databases for different endpoints

I have API written in lumen(laravel). I am using Eloquent for my models.
What I need to do is to use different databases based on url (endpoint).
For example I have http://apiprovider.com/api/v1/ as base API url and it connects to the api_v1 database, but I need to use another database if v2 is used http://apiprovider.com/api/v2 for instance api_v2 database.
All classes and laravel application should be the same, only different database according to version.
Database settings is stored in .env file.
Please suggest the right way to implement this ? Or at least possible ways.
Thanks.
It's just an idea, i haven't tried it but a simple way would be switching between the two databases from a middleware.
For example you could define the two connections available in database.php :
'connections' => [
'mysql1' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'mysql2' => [
'driver' => 'mysql',
'host' => env('DB_HOST_2', 'localhost'),
'database' => env('DB_DATABASE_2', 'forge'),
'username' => env('DB_USERNAME_2', 'forge'),
'password' => env('DB_PASSWORD_2', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
]
Then create a middleware and switch the DB in the handle method
public function handle($request, Closure $next)
{
//check the request URL and decide what DB to use
//set the DB for this request
Config::set('database.default', $dbname );
}
I think that Config::set('database.default', $dbname); will work only for the current request, but it would do what you need

Categories