This question already has answers here:
How to use multiple databases in Laravel
(7 answers)
Closed 5 months ago.
I'm using Laravel 5.5 and MySQL, and I want to connect to multiple databases. I read many articles and most of them suggest to set config/database.php first, and in the controller use following code to connect to database:
$result = DB::connection('mysql2')->select($);
It works for me, but I have multiple databases and have saved the host & port in the main database.
is it possible to query the database list and connection information from the database itself and then put it into the config/database.php?
Or I should add the database list and connection information manually?
I think you can refer to this How to make database query inside a config file?
where u can query the database and put it in your config file.
I found a solution. Share it to everyone :)
First, make a Connection Model.
Then, add code in the app/Providers/AppServiceProvider.php
//connections
if (\Schema::hasTable('connections')) {
$connections = \App\Models\Connection::all();
$db = \Config::get('database.connections');
foreach ($connections as $connection)
{
$db['cdb_'.$connection->id] = [
'driver' => 'mysql',
'host' => $connection->db_host,
'port' => $connection->db_port,
'database' => $connection->db_database,
'username' => $connection->db_user,
'password' => $connection->db_pass,
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci', //utf8_unicode_ci
'prefix' => '',
'strict' => false,
];
}
\Config::set('database.connections',$db);
}else{
\Config::set('database.connections',[]);
}
Schema::defaultStringLength(191);
Related
I have a situation where I'd like to dynamically choose the DB host for postgres DB connections in a Laravel application running in Docker. I don't particularly want to use ENV values or the config/database.php file because it is a one-off query to the external DB that I would prefer to embed in Helper Class.
These actually could go in the .env file:
PSQL_DB_PORT=5432
PSQL_DB_DATABASE=postgres
PSQL_DB_USERNAME=postgres
PSQL_DB_PASSWORD=postgres
and in my helper I can get the hostname for the remote (actually in Docker) postgres server, which will basically be something like:
postgres_index-db1, postgres_index-db2, postgres_index-db3, etc., but I need to fetch that dynamically and store it in a variable $host.
I tried playing around with a thing like this:
DB::disconnect('pgsql');
Config::set("database.connections.pgsql", [
'driver' => 'pgsql',
'host' => $host ,
'port' => env('PSQL_DB_PORT', '5432'),
'database' => env('PSQL_DB_DATABASE'),
'username' => env('PSQL_DB_USERNAME'),
'password' => env('PSQL_DB_PASSWORD'),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
]);
dd(DB::connection('pgsql'));
$query = "select DISTINCT value from maindicomtags where taggroup = 8 and tagelement = 128";
$names = DB::connection('pgsql')->select($query,[]);
and the dd(DB::connection('psql')) (a Laravel dump) statement actually shows the correct config, but when the query tries to execute it must be looking for the pgsql config in my config/database.php file because it throws an error:
Database connection [pgsql] not configured
because it must be looking for the config in the config/database.php file, and I removed the definition from there. I want it to use the connection that is defined above.
Is there a a way to do what I am trying to do. I could even just use the connection string for Postgres if that is possible.
Might actually be working because I might have had a typo earlier (e.g. psql vsl pgsql).
Does this seem like an adequate way to make that type of dynamic connection ? It is really just the host that will be different.
Instead of setting your config, just create a custom database connection using factory. The only downside - you will not be able to use Eloquent as it resolves connection by its name defined in configs. Also, avoid using env variables anywhere else than config files - create other config and use it instead. There is quite a chance something could break somewhere else if you change config on the go:
$factory = app(\Illuminate\Database\Connectors\ConnectionFactory::class);
$db = $factory->make([
'driver' => 'pgsql',
'host' => $host ,
'port' => $port ?? 5432,
'database' => $database,
'username' => $username,
'password' => $password,
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
]);
$names = $db->table('maindicomtags')
->where('taggroup', 8)
->where('tagelement', 128)
->distinct()
->pluck('value');
$db->disconnect();
In my project, I need to use multiple databases depending on each user where users table is in separate database.
First I get users database using Auth->user()->db and pass it to Config::set(). But, when I try to get data from the new database, Laravel tries to connect to the first one.
How can i fix it?
The users database is set in env file.
$db= Auth::user()->name;
Config::set('database.connections.sqlsrv', [
'driver' => 'sqlsrv',
'host' => 'localhost',
'port' => '1433',
'database' => $db
]);
$query = DB::connection('sqlsrv');
$posts = $query->table('posts')->get();
This question already has answers here:
How to connect to mysql with laravel?
(6 answers)
Closed 8 years ago.
I'm making a PHP application installer (something like Wordpress installation script) and I need to check mysql connection using host name, username, password and database provided by user during installation.
I'm using this code as a Laravel controller method to test connection:
public function TestDatabaseConnection(){
try {
$database_host = Config::get('config.database_host');
$database_name = Config::get('config.database_name');
$database_user = Config::get('config.database_user');
$database_password = Config::get('config.database_password');
$connection = mysqli_connect($database_host,$database_user,$database_password,$database_name);
if (mysqli_connect_errno()){
return false;
} else {
return true;
}
} catch (Exception $e) {
return false;
}
}
This code doesn't seem to properly test the connection. Function return value (true/false) doesn't depend whether user supplies db data at all, or if db data is correct/incorrect..
Fils /app/config/config.php contains the following array:
<?php return array('database_host' => 'localhost', 'database_name' => 'dbasename', 'database_user' => 'dbuser', 'database_password' => 'pass');
and it's being updated via form during installation process.
Is there any way to modify this code or maybe you have some other code suggestions?
Your question is:
How to test MySQL connection in PHP and Laravel?
But then you are setting up a standard PHP MySQLi connection like this:
$connection = mysqli_connect($database_host,$database_user,$database_password,$database_name);
Why would you do that? The whole purpose of using a framework is to work within the framework. And something that encompasses these two basic systems concepts:
Read a configuration file.
Establish a database connection.
Doing those things is something that pretty much every capable—and widely adopted—programming framework should be able to handle within it’s own structure & using it’s own methods.
So that said, looking at the Laravel documentation on “Basic Database Usage” shows the following. This is placed in your DB configuration file located in app/config/database.php.:
'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' => '',
),
The example has two distinct DB connections: One for read and the other for write, but that is not how most DB connections for simple projects work. So you can set this instead also using your settings:
'mysql' => array(
'host' => Config::get('config.database_host'),
'driver' => 'mysql',
'database' => Config::get('config.database_name'),
'username' => Config::get('config.database_user'),
'password' => Config::get('config.database_password'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Then to test that connection, you would just do this:
if(DB::connection()->getDatabaseName())
{
echo "Yes! successfully connected to the DB: " . DB::connection()->getDatabaseName();
}
But that said you are also saying:
I'm making a PHP application installer…
Why reinvent the wheel when PHP build systems such as Phing exist?
You can simply check whether the connection is made or not using this:
if(DB::connection()) {
// connection is made
}
Because you don't need to make connection manually. If the user provided right credentials in the app/config/database.php then the user will be able to query in the database but if you need to check the connection then given code above is able to check because if the connection is not made then an error will be thrown and on a valid connection the Illuminate\Database\MySqlConnection object will be returned. So, in this case it's also possible to use:
if(DB::connection() instanceof Illuminate\Database\MySqlConnection) {
// connection is made
}
So, according to your example of TestDatabaseConnection method you can do something like this:
public function TestDatabaseConnection(){
// Returns Illuminate\Database\MySqlConnection on successful
// connection; otherwise an exception would be thrown if failed
return DB::connection();
}
If you really want to catch the error of laravel db connection failure,
you can define this:
App::error(function(PDOException $exception, $code)
{
die('do what you want here');
});
I defined it inside:
/app/start/global.php
you can define it where ever you like.
I am trying to setup connections to multiple database under the same instance for correlation data analysis
Here is the basic idea of the connection code
$a = array('a','b','c');
$b = array('a','b','c');
foreach($a as $ac){
foreach($b as $bc){
Config::set('database.connections.'.$ac.'_'.$bc, array(
'driver' => 'mysql',
'host' => 'somehost',
'port' => '3306',
'database' => $ac.'_'.$bc,
'username' => 'user',
'password' => 'user',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => ''
));
}
}
There are about 40 different db in that instance, and could change rapidly, so I want to avoid permanently create the connection in the config file and generate the connection on the fly with user input. And from what I gather, the above code should auto append the array to database.connections (see laravel github ), but I am getting this error.
SQLSTATE[HY000] [2002] No such file or directory
if I change database.connections.".$ac.'_'.$bc to database.connections.mysql the code runs okay. So what am I missing here :( , I am calling that piece of code under the constructor of the first controller the input will hit.
Thank you very much for the help in advance
After playing around a bit, found out what's the problem.
After calling the code above in controller,
in model, not only you have to make the initial connection but also you have to include a table in that statement in order to divert the connection to the specific DB, otherwise it will fall back to default connection if you use the way that builder query example from Laravel documentation. So instead of doing
$this->query = DB::connection($ac.'_'.$bc);
$this->query = DB::table('sometable');
do it like
$this->query = DB:connection($ac.'_'.$bc)->table('sometable');
Then connection for $this->query will lock to the new database pointed.
I want to connect to another database sometimes.
I created a config.php with the database connection data.
But how can i tell laravel to connect to this database insted of using the config/database.php?
For example when using the Schema class.
Since no one seems to understand what i want.
I DON'T want to use the config/database.php, i want to use a different config file on a different location.
It sounds like you figured this out. Here's how I'd accomplish it anyway for other people coming in, or in case something useful is here for you.
First, Add a second connection in app/config/database.php. Note: That file path may change depending on your environment.
<?php
return array(
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database1',
'username' => 'user1',
'password' => 'pass1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'mysql2' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database2',
'username' => 'user2',
'password' => 'pass2'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
);
Second, in your code, you can use (as mentioned) the 2nd connection where you would like:
Schema::connection('mysql2')->create('users', function($table) {})
There's more documentation on this - see Accessing Connections.
Eloquent ORM
You can define the variable for "connection" in an eloquent class to set which connection is used. That's noted in the Basic Usage section.
See that variable on here on Github and the method which you can set to set the connection dynamically here.
Edit
The OP has made it clear that they do not wish to use the config/database.php file for config.
However without explaining further, I can't comment. I'm happy to help - sounds like it would be useful to know why the config/database.php file can't/shouldn't be used, as this can help us ascertain the problem and create a useful solution.
I believe you want to implement some kind of logical sharding where databases would be dynamically created.
In such scenario in laravel you can dynamically add a database config, like below
$conn = array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'DATABASE',
'username' => 'USERNAME',
'password' => 'SOME_PASSWORD',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
);
Config::set('database.connections.DB_CONFIG_NAME', $conn);
Now to connect via eloquent
MODEL::on('DB_CONFIG_NAME')->WHAT_EVER('1');
Incase of Query Builder you can do
$DB = DB::connection('DB_CONFIG_NAME');
use $DB->select() for querying now.
Hope this would help devs looking for a possible solution for this question
Remember that Laravel 4 is actually a collection of components, and you can use these components solo.
https://github.com/illuminate/database
There is an example here that shows off how interacting with the Capsule class works:
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
]);
// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
$capsule->setEventDispatcher(new Dispatcher(new Container));
// Set the cache manager instance used by connections... (optional)
$capsule->setCacheManager(...);
// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();
// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();
This is a bunch of bootstrapping that you'll need to run, so tuck it away somewhere in a function or method.
But, its absolutely possible.
There is a simpler solution. If you are using Larave 4 there is an option that worked for me. Recently they added $table variable that you can specify in your model. Refer to this link.
class User extends Eloquent {
protected $table = 'my_users';
}
If you are using MySQL, you can do the following:
class User extends Eloquent {
protected $table = 'mydbname.my_users';
}
If you are using SQL Server, you can do this:
class User extends Eloquent {
protected $table = 'mydatabase..my_users';
}
My Config file had DB1 specified but I created a model which wants to access DB2 in the same MySQL host. So this was a quick and dirty way to accomplish this.
Now I don't fully leverage Eloquent ORM all the time so this "hack" may not work with Many to Many or one to Many Eloquent methods.
One another idea I had but I didn't actually try was creating a stored procedure (routine) in DB1 and inside of that routine I can access DB2 tables by querying link this:
SELECT * from db2.mytable where id = 1;
To use a config file in another location, say src/config:
use Config;
$this->dbConfig = Config::get('appname::dbInfo.connections.test');
$this->database = $this->dbConfig['database'];
$this->username= $this->dbConfig['username'];
$this->password= $this->dbConfig['password'];
Where dbInfo is a simple php file in your app's src/config directory returning an array containing the element connections which is an array of database properties.
You can tell Laravel to use an external config file using:
Config::set("database.connections.test", $this->dbConfig);
DB::connection("test");
Edit bootstrap/start.php file and add your machine name (open terminal: hostname).
Add your machine to $env,
$env = $app->detectEnvironment(array(
'mymachine' => array('mymachine.local'),
));
Create a new path at 'app/config/mymachine'
Add a copy of database.php with new config params.