Notes from Ollie Read's article Laravel multi-tenancy, avoiding over engineering.
https://ollieread.com/articles/laravel-multi-tenancy-avoiding-over-engineering
App\Services\TenantManager
This gets/sets the current tennant. loadTenant() method houses the query to find the tenant.
In the AppServiceProvider, binds an instance of the TenantManager class to the Container.
Binds the Tenant model to the Container to use the TenantManager::getTenant() method.
IdentifyTentant middleware. Uses the TenantManager to recognise the tenant.
All tenant routes are wrapped in this middleware.
It gets the subdomain/domain/path to recognise the tenant.
Laravel can remove this tenant parameter from the Request object so it's not passed to Controllers.
$request->route()->forgetParameter('tenant');
Middleware uses the TenantManager::loadTenant().
route() method on the Tenant model.
return app('url')->route($name, array_merge([$this->slug], $parameters), $absolute);
Use a scope, App\Scopes\TenantOwnedScope. Applies the scope to the query Builder.
Also withoutTenancy() method, e.g. for admin areas.
Use a trait App\Concerns\OwnedByTenant to add this scope to models.
Trait uses a bootOwnedByTenant method to add the scope and sets the relation with static::creating().
And a BelongsTo tenant() method.
Copy the Unique and Exists rules from Illuminate\Validation\Rule and copy them to the TenantManager(), adding a conditional for the tenant.