I am trying to set up a Laravel (9.51) app that is a bundle of sites. All sites' user data is in one database, and each site has a database for its content. Using this article:
How to Use Multiple Database Connections in Laravel 8
And consulting the Laravel docs for Eloquent ORM, and this StackOverflow question:
How to use multiple databases in Laravel
I set up the two connections, set the $connection property in the model, and tried to save, and the app tries to save to the wrong database.
My code looks like this:
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=dbaseone
DB_USERNAME=userone
DB_PASSWORD='my first password'
DB_CONNECTION_2=mysql
DB_HOST_2=127.0.0.1
DB_PORT_2=3306
DB_DATABASE_2=numbertwodbase
DB_USERNAME_2=seconduser
DB_PASSWORD_2='a different password'
config/database.php
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mysql2' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST_2', '127.0.0.1'),
'port' => env('DB_PORT_2', '3306'),
'database' => env('DB_DATABASE_2', 'forge'),
'username' => env('DB_USERNAME_2', 'forge'),
'password' => env('DB_PASSWORD_2', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
App/Models/User.php
class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, HasFactory, Notifiable, Billable;
protected $connection = 'mysql2';
And in a service called in my controller, I have this:
use App\Models\User;
. . .
public function newUser(array $props) {
$user = new User();
$user->name = $props['name'];
$user['email'] = $props['email'];
$user->password = Hash::make($props['password']);
if($user->save()) {
//listener sends verification email
event(new RegisteredUser($user, $props['return']));
//logs in for later use
Auth::login($user);
return true;
} else {
return false;
}
}
The result is this error message:
Illuminate\Database\QueryException
PHP 8.2.0
9.51.0
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'dbaseone.users' doesn't exist
Table 'numbertwodbase.users' is the table the app should be trying to save to, and that table does exist.
Thank you
EDIT:
To answer StewieSWS question below, here is the relevant part of the config/auth.php file:
\
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
I see, in that case, the error message "Base table or view not found: 1146 Table 'dbaseone.users' doesn't exist" indicates that the default database connection is being used instead of the specified connection.
One thing you could try is to specify the connection when creating the model, like this:
$user = (new User)->setConnection('mysql2')->create($data);
Because you have the configuration for the the second connection in your config file,you can use the DB::connection('mysql2') method to execute queries against the second database connection.
For example:
$user = DB::connection('mysql2')->table('my_table')->get();
Related
I am working on a cms project. I was created a portal and thenn new database connection created. So,there is a table users i wan that if someone create new user in that portal then it will be added to the master database that is another database. So, in laravel how can we make connection with another database and save the data of the portal to our master database table also.
Trying to make a sync connection that if in cms portal if admin create a user then that data must be submitted to the master table.
You can do it like this:
In .env add the following: note that you can customize your connection to another database, like postgres/mariadb etc.. check the documentation here for supported databases: https://laravel.com/docs/9.x/database#introduction
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=db
DB_USERNAME=user
DB_PASSWORD=password
DB_CONNECTION_SECOND=mysql
DB_HOST_SECOND=localhost
DB_PORT_SECOND=3306
DB_DATABASE_SECOND=db2
DB_USERNAME_SECOND=user2
DB_PASSWORD_SECOND=password2
In config/database.php: note that you can customize your connection to another database, like postgres/mariadb etc.. check the documentation here for supported databases: https://laravel.com/docs/9.x/database#introduction
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mysql2' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST_SECOND', '127.0.0.1'),
'port' => env('DB_PORT_SECOND', '3306'),
'database' => env('DB_DATABASE_SECOND', 'forge'),
'username' => env('DB_USERNAME_SECOND', 'forge'),
'password' => env('DB_PASSWORD_SECOND', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
In the sample model:
class Job extends Model
{
protected $connection = 'mysql2';
}
I have a database which runs on local that I created with TablePlus. I can access it without any problem. I tested with Insomnia and I can get the info I need. I search how to connect to a second database that is live. I changed my .env file and my database.php to create another access to the second database. But I have an error message:
SQLSTATE[HY000][1045] Access denied for user 'root'#'host' (using passowrd: YES)
where host is the name I found in PHP MyAdmin in the variables tab.
How can I acccess the second DB ? What am I doing wrong ? Do I need to change the env('DATABASE_URL') for the second connection in database.php ?
.env:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=first_db
DB_USERNAME=root
DB_PASSWORD=root
DB_SECOND_CONNECTION=mysql2
DB_SECOND_HOST=host //(again, PHP MyAdmin -> variables tab)
DB_SECOND_PORT=3306
DB_SECOND_DATABASE=second_db
DB_SECOND_USERNAME=*username*
DB_SECOND_PASSWORD=*password*
database.php:
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'first_db'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', 'root'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mysql2' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_SECOND_HOST', 'host'), //(again, PHP MyAdmin -> variables tab)
'port' => env('DB_SECOND_PORT', '3306'),
'database' => env('DB_SECOND_DATABASE', 'secondd_db'),
'username' => env('DB_SECOND_USERNAME', 'username'),
'password' => env('DB_SECOND_PASSWORD', 'password'),
'unix_socket' => env('DB_SECOND_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
],
As suggested by #Collin above, the root user I was using didn't have the permissions. Creating a new user with all privileges in PHP MyAdmin solved the issue.
If you want to check if the database connection is actually accesable you could try the following.
First clear your config using the following command:
php artisan config:clear
Then check if the connection is accesable using the following code:
try {
DB::connection('mysql2')->getPdo();
} catch (\Exception $e) {
die("Could not connect to the database. Please check your configuration. error:" . $e );
}
If that doesn't work check if the user has the right permissions.
I'm doing a PHP Laravel (7.7.1) project with a mariadb database (10.4.12).
Actually, I'm trying to use a remote mariadb database (10.1.44) on a virtual private server under Debian Stretch (9.11) with my local mariadb database (10.4.12) under Macos Catalina (10.15.4).
The problem is that my Laravel project can't access to the remote database, I saw that the best solution is to use a ssh tunnel but no one solution worked for me.
Here is my .env file
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=name
DB_USERNAME=username
DB_PASSWORD=password
DB_CONNECTION_GAME=mysql
DB_HOST_GAME=11.22.3.444
DB_PORT_GAME=3306
DB_DATABASE_GAME=name
DB_USERNAME_GAME=username
DB_PASSWORD_GAME=password
Here is my database.php file
'mysql' => [
'driver' => env('DB_CONNECTION', 'mysql'),
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mysqlgame' => [
'driver' => env('DB_CONNECTION_GAME', 'mysql'),
'url' => env('DATABASE_URL_GAME'),
'host' => env('DB_HOST_GAME', '127.0.0.1'),
'port' => env('DB_PORT_GAME', '3306'),
'database' => env('DB_DATABASE_GAME', 'forge'),
'username' => env('DB_USERNAME_GAME', 'forge'),
'password' => env('DB_PASSWORD_GAME', ''),
'unix_socket' => env('DB_SOCKET_GAME', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
Here is my database model
class Whitelisted extends Model
{
/**
* The attributes that are mass assignable.
* #var array
*/
protected $fillable = [
'name', 'identifier'
];
protected $connection = 'mysqlgame';
protected $table = 'user_whitelist';
}
And finnaly, here is the error code from Illuminate
SQLSTATE[HY000] [2002] Connection refused (SQL: select * from `user_whitelist`)
What is the best solution to have two databases with one local and the other connected to a remote server ?
Thanks !
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(...);
I make Request to Validate requested values from controller action by this way:
namespace App\Http\Requests;
use App\Http\Requests\Request;
class AccountsRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
return TRUE;
}
public function rules() {
return [
'email' => 'email|required|max:255|unique:accounts',
'password' => 'min:6|required'
];
}
}
All is fine if I'm using the default database, but for this Validation I need to check the tables in other database. In config I have two databases:
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => database_path('database.sqlite'),
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'sait'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'mysql2' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'account'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
When I call the Validation, it is checking by "unique" rule in my default database so I need to change it, but I cannot found anywhere how to do this.
According to the docs unique - Custom Database Connection
instead of
'email' => 'email|required|max:255|unique:accounts',
you need to do
'email' => 'email|required|max:255|unique:mysql2.accounts',
I guessed its mysql2 as you didnt mention.
Did you see this in the docs for the 'unique' rule?
$verifier = App::make('validation.presence');
$verifier->setConnection('connectionName');
$validator = Validator::make($input, [
'name' => 'required',
'password' => 'required|min:8',
'email' => 'required|email|unique:users',
]);
$validator->setPresenceVerifier($verifier);
You can use the setConnection() method to specify how you want unique to be determined.