[Laravel5.1]複数のDBに接続させる

#はじめに
Laravelでプロジェクト作ってるとDBを複数に分けたい場合があると思います。
ありますよね？

調べてみたら結構簡単にできたので備忘録的な扱いとして手順を残しておきます。

#環境
![001.png](https://qiita-image-store.s3.amazonaws.com/0/165355/d4181d11-57dc-5ba8-320d-a5c32d9ab4b2.png)
簡単に言うとこんな感じです。
今回はすべてMySQLで構築しましたが、もちろん他のORDBと共存させることも可能みたいです。
本当はSQLServerと共存させたかったのですが、ドライバがないって怒られました。

configファイルに``sqlsrv``の文字があるのに標準でドライバがないってどういうことなのHomesteadさん...。
ドライバ入れたらいけるっぽいけど、工数取られそうだったので今回はオミット。
何か情報をお持ちの方がいればご教示ください:innocent:

#変更手順
次の場所を変更していきます。

+ /config/database.php
+ /.env(オプション)

##設定をベタ打ちする場合
```php:/config/database.php
    'connections' => [
        // Homestead標準のデータベース
        'mysql' => [ 
            '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,
        ],
        // Homestead上に作った他のデータベース
        'mysql_2' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', 'localhost'),
            'database'  => 'DB2',                        // データベース名のみ変更
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        // 別サーバー上のデータベース
        'mysql_3' => [
            'driver'    => 'mysql',
            'host'      => '192.168.10.15',              // Server2のIPアドレス
            'database'  => 'DB3',                        // Server2のデータベース
            'username'  => 'user2',                      // Server2のMySQLユーザー名
            'password'  => 'password2',                  // Server2のMySQLパスワード
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        ...
```

このように、下にどんどん接続先を足していきます。
基本的に接続先の変更がないのであれば、わざわざ``/.env``ファイルに書き足す必要もないかなぁとは思います。
一応``/.env``ファイルに追記していくやり方も掲載しときます。

##設定ファイルから拾う場合

```php:/config/database.php
    'connections' => [
        // Homestead標準のデータベース
        'mysql' => [ 
            'driver'    => 'mysql',
            'host'      => env('DB_HOST_1', 'localhost'),
            'database'  => env('DB_DATABASE_1', 'forge'),
            'username'  => env('DB_USERNAME_1', 'forge'),
            'password'  => env('DB_PASSWORD_1', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        // Homestead上に作った他のデータベース
        'mysql_2' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST_1', 'localhost'),
            'database'  => env('DB_DATABASE_2', 'forge'),
            'username'  => env('DB_USERNAME_1', 'forge'),
            'password'  => env('DB_PASSWORD_1', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        // 別サーバー上のデータベース
        'mysql_3' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST_3', 'localhost'),
            'database'  => env('DB_DATABASE_3', 'forge'), 
            'username'  => env('DB_USERNAME_3', 'forge'),
            'password'  => env('DB_PASSWORD_3', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        ...
```

```text:/.env
DB_CONNECTION=mysql
DB_HOST_1=127.0.0.1
DB_DATABASE_1=DB1
DB_DATABASE_2=DB2
DB_USERNAME_1=user1
DB_PASSWORD_1=password1

DB_CONNECTION=mysql
DB_HOST_3=192.168.10.15
DB_DATABASE_3=DB3
DB_USERNAME_3=user2
DB_PASSWORD_3=password2
```

こんな感じですね。こっちのほうは試してないですが。

#接続テスト
試しにこんな感じでテストしてみます。

```php:/app/Http/routes.php
Route::get('/dbtest/query', function(){
    // connection先を明示しなかった場合、デフォルト接続先のDB1を見に行く
    $rows = DB::select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

    // 当然、明示した接続も可能
    $rows = DB::connection('mysql_1')->select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

    // connection先を明示してDB2を見に行く
    $rows = DB::connection('mysql_2')->select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

    // connection先を明示してDB3を見に行く
    $rows = DB::connection('mysql_3')->select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

});
```

次に、モデルを定義して接続先を意識せずにDBを見に行きたいと思います。

```bash:console
php artisan make:model db2_table_sample
```

```php:/app/db2_table_sample.php
namespace App;

use Illuminate\Database\Eloquent\Model;

class db2_table_sample extends Model
{
    protected $connection = 'mysql_2';
}
```
```php:/app/Http/routes.php
Route::get('/dbtest/model', function(){
    // 特に接続先を明示しないでDB接続が可能
    $rows = \App\db2_table_sample::first();
    var_dump($rows);
});
```

ここまでできるんだったら外部DBへのリレーションとかも簡単に行きそうですね。
これは…すごいぞ…:innocent:

#別DBのテーブルをマイグレーションする
こういうことをするかどうかは別として、できるかどうかの確認がしたかったので。
基本的には同一サーバー上ならともかく、別サーバーのDBをいじくり回すことはなさそうな気もします。

##マイグレーションファイル作成
```bash:console
php artisan make:migration create_db3_tests
```

```php:/database/migrations/yyyy_mm_dd_His_create_db3_tests.php
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Sample extends Migration
{

    /**
     * Run the migrations.
     * @return void
     */
    public function up() {
        Schema::connection('mysql_3')->create('db3_tests', function(Blueprint $table){
            $table->increments('id');
            $table->string('test_text');
        });
    }

    /**
     * Reverse the migrations.
     * @return void
     */
    public function down() {
        Schema::connection('mysql_3')->drop('db3_tests');
    }

}
```

``Schema::connection('[connection名]')``がポイントですね。
あとは普通のマイグレーションと全く変わりません。

##マイグレーション実行
```bash:console
php artisan migrate --database=mysql_3
```

こちらは``--database=[connection名]``がポイント。
ちなみにここで、

```
[Illuminate\Database\QueryException]
  SQLSTATE[42000]: Syntax error or access violation: 1142 CREATE command denied to user 'user2'@'192.168.10.15' ...
```

的なエラーが出たら別サーバー側でそのユーザーが権限持ってないだけです。
一応その手順も。

```sql:console.192.168.10.15
mysql -u root -p

/* ユーザーリストを取得する */
select Host, User from mysql.user;
/*
+-----------+-------+
| Host      | User  |
+-----------+-------+
| 127.0.0.1 | root  |
| %         | user2 |
+-----------+-------+
*/

/* user2にすべての権限を与える */
grant all on *.* to user2;

/* user2の権限を確認する */
show grants for 'user2'@'%'\G
/*
*************************** 1. row ***************************
Grants for user2@%: GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' IDENTIFIED BY PASSWORD '...'
*/
```

ホントはセキュリティ上、上記のコマンド叩くとガバガバになっちゃうのでまずいんですが。

#所感
正直、別サーバーのDBに対してマイグレーションできるとまでは思っていませんでした。
いともたやすくリレーションできちゃうから、かなり幅が広がった感あります。
すでに作成したプロジェクトのDBを利用して色々やったり、あるいはマスタデータは別サーバーで管理してそのデータを見に行くとか、色々できそうですね。