I build a simple way to identify tenant with subdomain:
for example: user1.example.com, the tenant will be user1.
On the other hand, if user1 does not exist, the user1.example.com will response 404.
I define a Marco in service provider like following:
public function register()
{
$this->app->singleton('tenancy', function (Application $app) {
return new TenancyMananger($app);
});
}
public function boot()
{
Route::macro('tenancy', fn (Closure $groups) => Route::domain(sprintf('{tenant}.example.com'))
->middleware(['tenancy'])
->group($groups));
Route::model('tenant', Tenant::class);
}
Then, use middleware to init and identify the tenant:
public function handle(Request $request, Closure $next)
{
Tenancy::init($request->tenant);
return $next($request);
}
And I override the getRouteKeyName method on the Tenant model to use database column other than id:
public function getRouteKeyName()
{
return 'domain';
}
Finally, I write the following feature testing case to test it:
Route::tenancy(function () {
Route::get('/test', fn () => 'hello world');
});
$tenant = Tenant::factory()->create([
'domain' => 'demo',
'name' => 'demo name',
]);
$this->get(""demo.example.com/test')->assertStatus(200);
$this->assertEquals(Tenancy::tenant()->id, $tenant->id);
$this->assertEquals(Tenancy::domain(), $tenant->domain);
$this->assertEquals(Tenancy::name(), $tenant->name);
But I will get the error:
testing.ERROR: App\TenancyMananger::init(): Argument #1 ($tenant) must be of type App\Models\Tenant, string given
It seems like that route does not trigger the model binding so that $request->tenant int the middleware pass the string ( subdomain ) into the TenancyMananger.
Any idea what could be happening here?
Or I can not write the test like this...
Any help or guidance is much appreciated.
I use PHP 8.1, Laravel 9 and phpunit v9.5.27.
Thanks.