Laravelでのマルチテナントは、tenancy/tenancyを使用する。
tenancy/tenancyと、ベースの機能のみで必要な分は後から追加するtenancy/frameworkがある。
tenancy/framework推奨
$ composer require tenancy/framework
$ php artisan make:model Organization -m
create_organizations_table.php
public function up()
{
Schema::create('organizations', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->timestamps();
});
}
$ php artisan migrate
Organization.php
use Illuminate\Http\Request;
use Tenancy\Identification\Contracts\Tenant;
class Organization extends Model implements Tenant
{
use HasFactory;
protected $fillable = [
'name',
'subdomain',
];
protected $dispatchesEvents = [
'created' => \Tenancy\Tenant\Events\Created::class,
'updated' => \Tenancy\Tenant\Events\Updated::class,
'deleted' => \Tenancy\Tenant\Events\Deleted::class,
];
public function getTenantKeyName(): string {
return 'name';
}
public function getTenantKey(){
return $this->name;
}
public function getTenantIdentifier(): string {
return get_class($this);
}
}
Tenancy\Identification\Concerns\AllowsTenantIdentification を使うだけでもできる
-テナントが追加されたら、テナント用のデータベースを作成してマイグレーション
-テナントが更新されたらマイグレーション実行
-テナントが削除されたらデータベース削除
-テナントを識別するため、Resolverに登録
app/Providers/AppServiceProvider
use Tenancy\Identification\Contracts\ResolvesTenants;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
//
$this->app->resolving(ResolvesTenants::class, function(ResolvesTenants $resolver){
$resolver->addModel(Organization::class);
return resolver;
});
}
}
MySQLのデータベースドライバをインストール
$ composer require tenancy/db-driver-mysql
affects connections : テナントのDBにテナントのDBにアクセスできるようにする
$ composer require tenancy/affects-connections
tenancyの拡張パッケージは Event/Listner で構成
$ php artisan make:listener ResolveTenantConnection
/listeners/ResolveTenantConnection.php
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Tenancy\Identification\Contracts\Tenant;
use Tenancy\Affects\Connections\Contracts\ProvidesConfiguration;
class ResolveTenantConnection
{
public function handle(Resolving $event)
{
//
return $this;
}
public function configure(Tenant $tenant): array {
$config = [];
event(new Configuring($tenant, $config, $this));
return $config;
}
}
/app/Providers/EventServiceProvider.php
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
\Tenancy\Affects\Connections\Events\Resolving::class => [
App\Listeners\ResolveTenantConnection\ResolveTenantConnection::class,
],
Registered::class => [
SendEmailVerificationNotification::class,
],
];
}
$ composer require tenancy/hooks-migration
$ php artisan make:listener ConfigureTenantMigrations
use Tenancy\Hooks\Migration\Events\ConfigureMigrations;
use Tenancy\Tenant\Events\Deleted;
class ConfigureTenantMigrations
{
public function handle(ConfigureMigrations $event)
{
//
if($event->event->tenant){
if($event->event instanceof Deleted){
$event->disable();
} else {
$event->path(database_path('tenant/migrations'));
}
}
}
}
EventServiceProvider.php
use Illuminate\Support\Facades\Event;
use App\Listeners\ConfigureTenantMigrations;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
$this->app->resolving(ResolvesTenants::class, function(ResolvesTenants $resolver){
$resolver->addModel(Organization::class);
return resolver;
});
}
protected $listen = [
\Tenancy\Hooks\Migration\Events\ConfigureMigrations::class => [
ConfigureTenantMigrations::class,
],
];
}
$ php artisan make:listener ConfigureTenantSeeds
use Database\Tenant\Seeders\DatabaseSeeder;
use Tenancy\Hooks\Migration\Events\ConfigureSeeds;
use Tenancy\Tenant\Events\Deleted;
use Tenancy\Tenant\Events\Updated;
class ConfigureTenantSeeds
{
public function handle(ConfigureSeeds $event)
{
//
if($event->event->tenant){
if($event->event instanceof Deleted || $event->event instanceof Updated){
$event->disable();
} else {
$event->seed(DatabaseSeeder::class);
}
}
}
}
EventServiceProvider.php
protected $listen = [
\Tenancy\Affects\Connections\Events\Resolving::class => [
App\Listeners\ResolveTenantConnection\ResolveTenantConnection::class,
],
\Tenancy\Hooks\Migration\Events\ConfigureMigrations::class => [
ConfigureTenantMigrations::class,
],
\Tenancy\Hooks\Migration\Events\ConfigureSeeds::class => [
ConfigureTenantSeed::class
],
Registered::class => [
SendEmailVerificationNotification::class,
],
];
.env.testing
TENANT_SLUG=test
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=test_central
DB_USERNAME=root
DB_PASSWORD=password
あれ? これでどうやって実装するのかようわからんな。。