Использование нескольких баз данных в проекте Laravel

Источник: «Use several databases within your Laravel project»
Как использовать несколько баз данных в проекте Laravel и управлять разделёнными записями в базе данных.

Пример проекта Laravel можно найти на нашем репозитории Github.

Стремясь сохранить ясность в каждом из своих проектов, я разделяю базы данных в зависимости от выполняемой ими роли. Например, этот блог включает в себя несколько баз данных: одна специально для блога, другая — для аналитики. В этой статье объясняется, как это сделать.

Новый проект Laravel уже содержит в своём файле .env информацию, связанную с базой данных, включая установленное по умолчанию соединение mysql. Мы будем работать с двумя базами данных: one и two. Также будет установлено соединение с one (опционально).

.env

До:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<database-name>
DB_USERNAME=
DB_PASSWORD=

После:

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=

Информация из файла .env по умолчанию отражается в конфигурационном файле 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'),
]) : [],
],
...
]

Продублируем информацию о подключении столько раз, сколько будет подключений.

'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'),
]) : [],
],

Затем необходимо дать указание миграциям мигрировать в разные созданные базы данных:

Это позволяет сделать статическая функция connection('<connection-name>') фасада Schema, которую мы добавляем в функции up() и 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' );
}
};

Далее необходимо модифицировать модели, связанные с миграциями, указав их связь с базой данных через атрибут $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';
}

Теперь мы можем запустить команду миграции php artisan migrate. По умолчанию эта команда использует значение, заданное параметром DB_CONNECTION. Если оно не определено в файле .env, то его необходимо указать в команде php artisan migrate --database=one.

Для проверки работоспособности мы можем быстро реализовать анонимную функцию, вызываемую основным маршрутом.

routes/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 );
});

Затем эти значения создаются в соответствующих базах данных и становятся видимыми в браузере.

В случае необходимости обновления базы данных с помощью команды php artisan migrate:fresh следует отметить, что будет обновлена только база данных по умолчанию, т.е. та, которая указана в DB_CONNECTION. К сожалению, Laravel пока не поддерживает одновременное обновление нескольких баз данных.

Для обновления базы данных, не являющейся базой по умолчанию, необходимо использовать команду php artisan db:wipe --database=<database-name>. Эту команду можно повторить для каждой дополнительной базы данных. После того как все базы данных будут корректно очищены с помощью команды db:wipe, можно без ошибок приступать к выполнению команды php artisan migrate:fresh.

Можно также разработать собственную команду, автоматизирующую выполнение различных задач по очистке базы данных.

Дополнительные материалы

Предыдущая Статья

Поддержка Bun в Laravel Sail и Forge

Следующая Статья

Повышение эффективности кодирования с соглашениями об именовании CSS