Laravel 5 でマルチテナント アプリケーションを構築しようとしています。Hyn や AuraEQ などの既存のパッケージがあることは知っていますが、これらはまだ理解しにくく、独自の (簡略化された) バージョンを作成したいと考えています。このようにして、私はボンネットの下で何が起こっているかを正確に知っています。始める前にインターネットでほとんどすべてを読みましたが、このテーマに関する情報はあまりありません。
私が念頭に置いているアプローチは非常に簡単です。
- でテナントを定義し
app/config/tenant.php
、対応するデータベース接続を で定義しますapp/config/database.php
。テナントを「マスター」データベースに保存するのはやり過ぎだと思います。 - サービス プロバイダーを登録してマルチテナントを有効にする
- (アクティブな) テナントを検出する IoC コンテナーにシングルトンを登録します。
- すべての Eloquent モデルを拡張し
getConnectionName()
、アクティブなテナント データベース内でクエリをオーバーライドする
すべての Web サイト (テナント) には、ストレージ パス内に独自のフォルダーがあります。「coding.com」という名前の Web サイトがあるとします。パスは次のようになりますapp/storage/tenants/coding-com
。現在、テナントには独自のビューとルートがあります。
これまでのところ、これはコードです:
class TenantServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->app->singleton('Tenant', function () {
$tenants = config('tenant.hosts');
$host = Request::server('HTTP_HOST');
if(array_key_exists($host, $tenants)) {
return $tenants[$host];
}
return null;
});
$tenant = $this->app->make('Tenant');
$directory = tenant_path($tenant);
if($tenant && is_dir($directory)) {
// Load views from the current tenant directory
$this->app['view']->addLocation($directory . '/views');
// Load optional routes from the current tenant directory
if(file_exists($directory . '/routes.php')) require_once $directory . '/routes.php';
}
// Load base views, these will be overridden by tenant views with the same name
$this->app['view']->addLocation(realpath(base_path('resources/views')));
}
}
テナントの定義:
return [
/**
* Base path of the tenant's directory.
*/
'path' => storage_path('tenants'),
/**
* This is where the tenants are defined.
*/
'hosts' => [
'coding.com' => [
'id' => 'coding-com', // Connection within config/database.php is also named coding-com
'https' => false,
],
'other.com' => [
'id' => 'other-nl',
'https' => false,
]
]
];
getConnectionName()
そして、メソッドをオーバーライドする「TentantModel」という名前のクラスを使用して、すべての Eloquent モデルを拡張する必要があります。
/**
* Get the current connection name for the model.
*
* @return string
*/
public function getConnectionName()
{
$tenant = app()->make('Tenant');
if($tenant) {
return array_get($tenant, 'id');
}
return parent::getConnectionName();
}
コードの大きな塊で申し訳ありませんが、これによりアイデアが理解しやすくなります。
これは私にいくつかの質問をもたらします:
- テナントごとに資産を個別に管理するにはどうすればよいですか?
- シングルトンの使用はこのアプローチに意味がありますか? ある種のグローバル変数を持つことが思いついたのはこれだけで、うまく機能しますが、シングルトンがこの種のものを対象としているかどうかは疑問です。
- このアプローチにマイナス面はありますか?これを考えたときに考慮しなかったことはありますか?
1つだけ答えていただければ幸いです。前もって感謝します!