Best way to connect multiple databases in Laravel [duplicate] - php

This question already has answers here:
How to use multiple databases in Laravel
(7 answers)
Closed 5 years ago.
I am creating a multi-tenant application in which, based on the sub-domain, I am connecting to a database of that particular tenant.
Here is code to do that:
// To connect with a subdomain - the entry will be in config/database.php.
public static function connectSubdomainDatabase($dbname)
{
$res = DB::select("show databases like '{$dbname}'");
if (count($res) == 0) {
App::abort(404);
}
Config::set('database.connections.subdomain.database', $dbname);
//If you want to use query builder without having to specify the connection
Config::set('database.default', 'subdomain');
DB::reconnect('subdomain');
}
Is it the best way to connect with a database or is there any problem that because I am thinking from the performance point of view because every time I am connecting with the database when there are different subdomains. What is the best possible way to do that?

This is nearly the best way to do this. In the end, it's all opinion anyway. However, I would create a connection in the configuration file for each of the subdomains. Then, in your connectSubdomainDatabase() function, I would get the current subdomain instead of passing a database name. You can already specify a connection in laravel, the only place you should be using database names is in the config file.
So, something like this:
// To connect with a subdomain - the entry will be in config/database.php.
public static function connectSubdomainDatabase()
{
// Break apart host
$urlParts = explode('.', $_SERVER['HTTP_HOST']);
// Change default connection
Config::set('database.default', $urlParts[0]);
}
Where the config/database.php connections is:
'connections' => [
'subdomain1' => [
'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,
],
'subdomain2' => [
'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,
],
],

Related

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(...);

Multiple databases in Laravel PHP [duplicate]

This question already has answers here:
How to use multiple databases in Laravel
(7 answers)
Closed 5 years ago.
We are building a multi-tenant application. Through the admin interface, we will add new tenant as and when required. This application needs to work with 1+n database.
1 Main DB with about 5 tables.
n DBs for each tenant that we create. The tenant specific database may reside on the separate db server altogether.
Question:
What is the best way to achieve this ?
Where do we store the the db connection information for each tenant ?
Sometime, we may have to fire join queries on tables in tenant and main db.
How would this work?
Thanks in advance for reading and any possible solution please.
Google is your friend, so is the documentation:
https://laravel.com/docs/5.4/database#using-multiple-database-connections
config/database.php
And add a new connection for each database-connection you want to use.
To switch connections:
$users = DB::connection('foo')->select(...);
We can set the DB connection in config/database.php in connections part:
'connections' => [
//Our primary DB
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
//Secondary DB
'mysql2' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB2_DATABASE', 'secondary'),
'username' => env('DB2_USERNAME', 'forge'),
'password' => env('DB2_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
],
And for Model we can add
class User2 extends Model
{
protected $connection = 'mysql2';
}
And in migration we can use connection method.
Schema::connection('mysql2')->create('table')
And if you use Eloquent ORM we can use setConnection('mysql2') on it.
$user = new User2;
$user->setConnection('mysql2');
This answer based on this question
In my case a wont use multi-tenant
store child db configurations in main database
set child db params in middleware
use $connection = 'child' in needed models
join is not possible, because may be different servers, but huge part of relations is work propertly (not whereExists, withCount.. etc)
Hope it`s help

Laravel: connect to databases dynamically

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

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

Laravel different config/database.php for production and development

I'm developing Laravel app on my local server where I have database and also I'm putting in online in production environment.
Each environment has different db connection information. So far I dealt with this just commenting information when I'm committing like this:
'mysql' => [
'driver' => 'mysql',
'host' => $host,
'database' => $database,
'username' => $username,
'password' => $password,
// 'host' => env('DB_HOST', 'localhost'),
// 'database' => env('DB_DATABASE', 'forge'),
// 'username' => env('DB_USERNAME', 'forge'),
// 'password' => env('DB_PASSWORD', ''),
// 'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
but this is sure wrong approach. How can I set different database connection information for each environment is some better way?
Use the .env file instead.. Have a .env in your production and one in your development..
Take a look at your .env.example
Laravel Environment Configuration Documentation

Categories