Laravel 5.7 でフル機能マルチテナント・SaaS型アプリ基盤をゼロから3時間で構築するの付録記事。
LaravelでマルチテナントSaaS基盤を作ったはいいけど、管理画面構築を手抜き効率化したいのでlaravel-adminを導入する話です。
方針
- LaravelでマルチテナントSaaS基盤をもとにアプリを開発する前に、各テナントごとに管理画面を持たせる基盤も作っておく。
- テナントを作成したら、管理画面も自動的に準備完了になるようにする。
- 管理画面ユーザーとフロントエンドユーザーは別のテーブルで管理する。ログイン管理も別。
- フロントエンドのRoleやPermission管理画面も作りやすい状態にする。
参考記事
Laravel 5.7 laravel-adminを導入する
laravel-adminで管理画面を速攻で構築する。
では構築
Laravel 5.7 でフル機能マルチテナント・SaaS型アプリ基盤をゼロから3時間で構築する Part3が完了している状態が前提です。
- Laravel 5.7が動作している。
- Tenancy Hynが入っている。
- laravel-permissionが入っている。
- テナントを簡単に作ったり消したりできる。
laravel-adminをプロジェクトに入れます。
composer require encore/laravel-admin
php artisan vendor:publish
で
Encore\Admin\AdminServiceProvider
を選択。すると以下のようにファイルがコピーされます。
Copied Directory [\vendor\encore\laravel-admin\config] To [\config]
Copied Directory [\vendor\encore\laravel-admin\resources\lang] To [\resources\lang]
Copied Directory [\vendor\encore\laravel-admin\database\migrations] To [\database\migrations]
Copied Directory [\vendor\encore\laravel-admin\resources\assets] To [\public\vendor\laravel-admin]
さて、次はインストールですが、php artisan admin:install
してしまうとシステムデータベースにlaravel-admin用データベースが作られてしまいます。
マルチテナントなのでデータベースはテナント作成時にマイグレーションおよびシーディングするべきですから、そのように変更してからインストールします。
laravel-adminのインストールコンソールコマンドをextend
して自前インストールコマンドを作る作戦を取ります。
laravel-adminで提供されるadmin:install
Artisanコマンドでは、データベースの作成(Migration+Seeding)と、プログラムコードのコピーが行われていますが、データベースの作成はスキップしてコードのインストールだけ実施するようadmin:install4hyn
を作成します。
app/Console/Commands/LaravelAdminInstall.php
を新設。その中にArtisanコマンドadmin:install4hyn
を新設します。
php artisan make:command LaravelAdminInstall
<?php
namespace App\Console\Commands;
use Encore\Admin\Console\InstallCommand;
class LaravelAdminInstall extends InstallCommand
{
/**
* The console command name.
*
* @var string
*/
protected $signature = 'admin:install4hyn'; // Our install command
/**
* The console command description.
*
* @var string
*/
protected $description = 'Install the admin package for Tenancy Hyn'; // Modified description
/**
* Install directory.
*
* @var string
*/
protected $directory = '';
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
// $this->initDatabase(); // We do not migrate database at this moment.
$this->initAdminDirectory();
}
}
これを実行。
php artisan admin:install4hyn
するとアプリにコードが埋め込まれます。すべてapp/Admin
以下に配置されていますね。
Admin directory was created: \app\Admin
HomeController file was created: \app\Admin/Controllers/HomeController.php
AuthController file was created: \app\Admin/Controllers/AuthController.php
ExampleController file was created: \app\Admin/Controllers/ExampleController.php
Bootstrap file was created: \app\Admin/bootstrap.php
Routes file was created: \app\Admin/routes.php
次に、テナント作成時にlaravel-adminに必要なテーブルが作られるように、Migrationファイルをdatabase/migrations
からdatabase/migrations/tenant
に移動(コピーではなく)します。
xxxx_xx_xx_xxxxxx_create_admin_tables.php
の1個だけです。
テーブルの中身はlaravel-adminのコアにあるSeederを呼ぶ仕様みたいなので、''CreateTenant.php''(または親記事のおまけ1改造を行った場合はTenant.php)に追記。
...
use Artisan;
...
$admin = static::makeAdmin($name, $email, str_random()); //これはもとからある
static::makeAdminAdmin(); //これを追記
...
private static function makeAdminAdmin(){
$userModel = config('admin.database.users_model');
if ($userModel::count() == 0) {
Artisan::call('db:seed', ['--class' => \Encore\Admin\Auth\Database\AdminTablesSeeder::class]);
}
}
...
一応これでテナント作成したらhttp://テナント名.ベースURL/admin
にアクセスできます。
User: admin, Password: adminでログインしようとすると、
Invalid catalog name: 1046 No database selected (SQL: select * from `admin_users` where `username` = admin limit 1)
これはlaravel-adminがテナントデータベースを見に行ってないためです。
今回はRouterの部分で、「laravel-adminのURLに入っていて、なおかつTenancyがテナントを認識していたら」、強制的にテナントデータベースを読みに行くようにapp/Admin/routes.php
を編集します。
<?php
use Illuminate\Routing\Router;
// Tenancy patch
$hostname = app(\Hyn\Tenancy\Environment::class)->hostname();
if(Request::is(config('admin.route.prefix')."*") && $hostname){
Config::set('database.default', 'tenant');
}
...
config('admin.route.prefix')
は、laravel-admin設定でURLのadmin
を好きなスラッグに変更できるので、それに対応させています。
では気を取り直してhttp://テナント名.ベースURL/admin
からログインしてみましょう。
ちゃんとテナント専用管理画面が出ましたね。
あとはユーザー管理画面、権限管理画面を作成し、またアプリに必要な管理画面を作っていけばOKです。
残る課題
残念ながらこの方法は完ぺきというわけではなく、1つ問題が残っています。
テナント用に管理画面を開発しても、新しくテナントを作った時には、メニューバーがデフォルトのままになるし、権限設定も空の状態からスタートします。これは、メニューバーの設定がデータベースに記録されているため、開発内容がテナントのデータベースに記録されており、新しく作ったテナントには反映されないためです。もちろんRouteやControllerは存在するので、画面アクセスはできるんですけどね。
対処としては、いったんデフォルト状態を作ったテナントを準備し、そのデータベースからSeederを手作りしなくてはいけなさそうです。まあ、これくらいは仕方ないですね。