マルチテナントのLaravelアプリを作りたいと考えていますか?各テナントのデータベースを分けて管理したり、テナント管理ユーザーを割り当てたり、テナント内で権限管理できるようにしたり、テナントの作成や削除を自動化したり、その後のテナント管理UI構築まで考えた形で作ったりしたいと考えていますか?そのために必要なプラグインのチュートリアルが不親切で意味が分からずイライラしたりしていますか?
もしそうだとしたら、この記事を読んでいるあなたは正しい場所にたどり着いています。
これは、今回の参考記事の冒頭部分の意訳です。(今回の記事に合うように、内容を少し端折ってます)
I would like to show the big thanks to Ashok who is the author of the article referred.
この記事では、Laravelでマルチテナントアプリを作成する方法を、備忘録を兼ねてまとめていきます。お仕事での調査ですが、自社用調査であり、まあこれくらいいいかということで、日本のLaravel応援、日本の技術者応援ということで情報公開します。
※ちなみに、お仕事受けることもできますのでご相談ください。うちはニューヨークの会社です。
正直言って、この方法はとてもよくできています。これまでにあった小手先の技ではなく、完全にコントロールされたテナント管理が可能になります。今使わないとしても、知っておいて損はないはずです。
はじめに
Laravelは、PHPの世界だけではなく様々なフレームワークと比べても大変優秀です。私もこれまで.Net環境なども含めいくつかのMVC Webアプリフレームワークを扱ってきましたが、Laravelは中規模アプリを作成する上で他に勝るとも劣らない環境と言えます。特にそのエコシステムは優秀で、シンプルかつわかりやすいだけでなく、素晴らしいドキュメントやチュートリアルもそろっています。
唯一の問題は、ちょっと複雑なアプリを組もうとすると、途端に情報が少なくなることです。今回のマルチテナントアプリはまさにそうで、英語も含めてほとんど情報がありません。実際にはLaravelでマルチテナントアプリを作ることは、とても簡単なのに。私は調査や最新版への対応のためのコード修正まで全部含めて1日でマルチテナントアプリの基本部分を作り終えました。ここにまとめた内容があれば3時間もあれば十分でしょう。
この記事のゴール
この記事では、マルチテナントアプリの基本部分を作り終えるところまでを具体的に書きます。
マルチテナント実現のため、Laravel Tenancy Hynを利用します。
マルチテナントアプリの仕様
今回の「マルチテナントアプリ」は、以下のような仕様を目指します。
- アプリのソースコードは1つ。テナントごとにコピーしない。
- システム(テナント管理)データベースと、テナントデータベースはわける。
- テナントデータベースは、テナント1つにつき1つとする。
- テナントを作ると、テナントデータベースと専用データベースユーザーが作られる。
- テナントを消すと、テナントデータベースと専用データベースユーザーが削除される。
- システムデータベース用のMigrationとテナントデータベース用のMigrationは分ける。
- コマンドラインからMigrationしたら、システムデータベース用Migrationだけが実行される。
- テナントを作った時、テナントデータベース用Migrationを実行してデータベースを初期化する。
- ユーザー管理はテナントごとに独立させる。
- テナントごとにユーザーの権限を設定できるようにする。
- テナントを作成した時に自動的にテナント管理者に招待状を送付し、パスワード設定させる。
- テナント画面からシステムデータベースの情報にアクセスできる余地を残しておく。
要件
Laravelやマルチテナントライブラリーによって、構築方法やソースコードが違ってきます。参考記事ではTenancy Hyn 5.1を使っていますが、この記事では最新の5.3を使います。5.2からCustomerが廃止されているので、参考記事とはソースコードが異なります。
この記事はWindows 10 ProにXAMPP 7.2.12を導入した状態で書いています。
重要なバージョンは以下です。
- Laravel 5.7
- Tenancy Hyn 5.3
- MariaDB 10.1.37 (XAMPP 7.2.12に入っているもの)
テナントを作成できるところまで作る
空のプロジェクトを作成する
まず空のLaravelプロジェクトを作成します。(必要に応じバージョンを指定してください) 名前はここでは参考記事に倣ってtownhouse
にします。
composer create-project --prefer-dist laravel/laravel townhouse
今回はXAMPP 7.2.12に入っているMariaDB 10.1.37を使うので、Providers/AppServiceProvider.php
のboot()内にStringの長さ制限を追記しておきます。
...
use Illuminate\Support\Facades\Schema;
...
public function boot()
{
//
Schema::defaultStringLength(191);
}
システムデータベースを作成する
システムデータベースを作成します。ここでは、参考記事に倣ってtownhousedb
という名前にします。
さらにシステムデータベースユーザーを作ります。このユーザーは、テナントのデータベースを作成するときに使われるユーザーなので、GRANT OPTION
を指定する必要があります。詳しくはこちら。開発用データベースなら、最上位権限を与えておけばいいでしょう。
Laravelにシステムデータベースを登録する
まずconfig/database.php
のconnections
セクションに、以下を追記します。
// Tenancy
'system' => [
'driver' => env('TENANCY_CONNECTION', 'mysql'),
'host' => env('TENANCY_HOST', '127.0.0.1'),
'port' => env('TENANCY_PORT', '3306'),
'database' => env('TENANCY_DATABASE', 'tenancy'),
'username' => env('TENANCY_USERNAME', 'tenancy'),
'password' => env('TENANCY_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
]
次に、.env
の末尾に、以下を追記します。
TENANCY_CONNECTION=mysql
TENANCY_HOST=127.0.0.1
TENANCY_PORT=3306
TENANCY_DATABASE=townhousedb
TENANCY_USERNAME=システムユーザー名
TENANCY_PASSWORD=システムユーザーパスワード
TENANCY_USERNAME
とTENANCY_PASSWORD
は、さっき作ったシステムデータベースユーザーの情報を入れます。
マルチテナントライブラリーTenancy Hynをインストールする
※この記事は、Hynバージョン5.3を利用する前提で書かれています。バージョンが変わると大きく仕様が異なってサンプルコードが動作しませんので十分注意してください。特に参考記事で使っている5.1から5.2でCustomerテーブルが廃止されるという大きな変更があります。
composer require hyn/multi-tenant
今回MariaDBを使うので(MySQLでも同じ)、以下の記述を.env
に追記します。詳しくはHynのドキュメントで。
LIMIT_UUID_LENGTH_32=true
さらに、マルチテナントアプリを実現するために重要な「テナントのMigrationをシステムのMigrationと分ける」の準備をしておきます。database/migrations
にある以下の2つのファイルを、テナント用の特別なフォルダdatabase/migrations/tenant
を新しく作ってそこに移動(コピーではない)させます。
2014_10_12_000000_create_users_table.php
2014_10_12_100000_create_password_resets_table.php
これにより、あとでテナントを作った時に、これらのMigrationが自動的に実行されます。特別なコーディングは不要です。
最後に、プロジェクトをマルチテナントアプリにコンバートします。参考記事とは違って、Tenancy Hynの公式の方法を使います。
php artisan vendor:publish --tag=tenancy
Tenancy Hynに必要なテーブルを作ります。
php artisan migrate --database=system
データベースを直接見ると、hostnames
, migrations
, それに websites
のテーブルがあるはずです。users
やpassword_resets
テーブルはないのが正解です。
テナント作成用artisanコマンドを作る
テナント作成のUIは今回は作りません。マルチテナントアプリには必ずしもテナント管理UIが必要というわけではなく、契約されたらエンジニアがテナントを作ればよい場合もありますから、この記事ではシンプルにテナント作成用artisanコマンドを作るにとどめます。動作は単純なので、artisanコマンドを参考にUIをあとで作るのは簡単です。
まずはartisanコマンドのひな型を作ります。
php artisan make:command CreateTenant
出来上がったapp/Console/Commands/CreateTenant.php
の中身を以下のようにします。
php:app/Console/Commands/CreateTenant.php