Blog / Utiliser plusieurs bases de données pour un même projet Laravel
5 min - 01 Sep 2023
TL;DR: Comment utiliser plusieurs bases de données au sein d'un même projet Laravel et séparer la gestion des informations.
Vous trouverez le code source via ce Github Repository. Découvrez en plus sur Capsules ou X.
Dans un souci de clarté pour chacun de mes projets, je sépare mes bases de données en fonction du rôle qu’elles ont. Ce blog, par exemple, comporte plusieurs bases de données : une pour le blog proprement dit et une autre pour l’analytique. Cet article explique comment procéder.
Un nouveau projet Laravel contient déjà, dans son fichier .env
, des informations relatives à la base de données, dont la connexion par défaut mysql
. Nous partirons sur deux bases de données MySQL : one
et two
. Ainsi qu’une connexion à one
devenant la base de données par défaut.
.env
Avant DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=<nom-de-la-base-de-donnees> DB_USERNAME= DB_PASSWORD= Après DB_CONNECTION=one DB_ONE_HOST=127.0.0.1 DB_ONE_PORT=3306 DB_ONE_DATABASE=one DB_ONE_USERNAME= DB_ONE_PASSWORD= DB_TWO_HOST=127.0.0.1 DB_TWO_PORT=3306 DB_TWO_DATABASE=two DB_TWO_USERNAME= DB_TWO_PASSWORD=
Dans le cas de bases de données SQLite stockées dans le dossier database
:
DB_CONNECTION=one
DB_ONE_DATABASE=one
DB_TWO_DATABASE=two
Les informations du fichier .env
par défaut sont reprises dans le fichier de configuration database.php
.
config/database.php
'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', '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'),
]) : [],
],
...
]
Dupliquons ces informations autant de fois qu’il y a de connections.
'connections' => [
'one' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_ONE_HOST', '127.0.0.1'),
'port' => env('DB_ONE_PORT', '3306'),
'database' => env('DB_ONE_DATABASE', 'forge'),
'username' => env('DB_ONE_USERNAME', 'forge'),
'password' => env('DB_ONE_PASSWORD', ''),
'unix_socket' => env('DB_ONE_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'),
]) : [],
],
'two' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_TWO_HOST', '127.0.0.1'),
'port' => env('DB_TWO_PORT', '3306'),
'database' => env('DB_TWO_DATABASE', 'forge'),
'username' => env('DB_TWO_USERNAME', 'forge'),
'password' => env('DB_TWO_PASSWORD', ''),
'unix_socket' => env('DB_TWO_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'),
]) : [],
],
...
]
Dans le cas de bases de données SQLite stockées dans le dossier database
:
'connections' => [
'one' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => database_path(env('DB_ONE_DATABASE', 'database').'.sqlite'),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
'two' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => database_path(env('DB_TWO_DATABASE', 'database').'.sqlite'),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
...
]
Il faut alors indiquer aux migrations de migrer vers les différentes bases de données créées :
one
→ 2023_08_31_000000_create_foos_table.php
two
→ 2023_08_31_000001_create_bars_table.php
La fonction statique connection( '<connection-name>' )
de la Facade Schema permet cela, que l’on ajoute dans la fonction up()
et down()
.
2023_08_31_000000_create_foos_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up() : void
{
Schema::connection( 'one' )->create( 'foos', function( Blueprint $table )
{
$table->id();
$table->timestamps();
});
}
public function down() : void
{
Schema::connection( 'one' )->dropIfExists( 'foos' );
}
};
2023_08_31_000001_create_bars_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up() : void
{
Schema::connection( 'two' )->create( 'bars', function( Blueprint $table )
{
$table->id();
$table->timestamps();
});
}
public function down() : void
{
Schema::connection( 'two' )->dropIfExists( 'bars' );
}
};
Il faut ensuite modifier les models relatifs aux migrations pour leur indiquer leur connection avec la database via l’attribut $connection
.
App\Models\Foo.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Foo extends Model
{
protected $connection = 'one';
}
App\Models\Bar.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Bar extends Model
{
protected $connection = 'two';
}
Nous pouvons dès maintenant lancer la migration php artisan migrate
. Par défaut, cette commande utilise la valeur donnée par DB_CONNECTION
. Si celle-ci n’est pas définie dans le fichier .env
, il faut alors l’indiquer dans la commande php artisan migrate --database=one
.
Afin de tester la fonctionnalité, nous pouvons rapidement implémenter une fonction anonyme lors de l’appel à la route principale.
web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Foo;
use App\Models\Bar;
Route::get( '/', function()
{
$foo = Foo::create();
$bar = Bar::create();
dd( $foo, $bar );
});
Les valeurs sont alors créées dans les bases de données respectives et visibles dans le browser.
Dans le cas où une actualisation des bases de données serait nécessaire en utilisant la commande php artisan migrate:fresh
, il est bon de noter que seulement la base de données par défaut, c'est-à-dire celle indiquée par DB_CONNECTION
, sera rafraîchie. Malheureusement, Laravel ne supporte pas [ encore ] le rafraîchissement de multiples bases de données en même temps.
Pour rafraîchir une base de données qui n'est pas celle par défaut, il est nécessaire d'utiliser la commande php artisan db:wipe --database=<database-name>
. Cette commande peut être répétée pour chaque base de données additionnelle. Une fois que toutes les bases de données ont été correctement nettoyées avec db:wipe
, vous pouvez ensuite procéder sans erreurs avec php artisan migrate:fresh
.
Vous pouvez aussi développer votre propre commande qui automatiserait les différentes tâches nécessaires pour nettoyer votre base de données.
Ravi d’avoir pu aider.