Tenant Routes
Routes within routes/tenant.php
will have the web
and tenancy
middleware groups automatically applied on them.
Just like routes/web.php
, these routes use the App\Http\Controllers
namespace (you can configure this)
If a tenant cannot be identified, an exception will be thrown. If you want to change this behavior (to a redirect, for example) read the Middleware Configuration page.
Middleware
The package automatically adds the InitializeTenancy
middleware to the global middleware stack. This middleware checks if the current domain is not part of tenancy.exempt_domains
. If not, it attempts to identify the tenant based on the current hostname. Once the tenant is identified, the database connection, cache, filesystem root paths and, optionally, Redis connection, will be switched.
After the global middleware is executed, the controllers are constructed.
After that, the route middleware is executed.
All route groups in your application should have the \Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains
middleware applied on them, to prevent access from tenant domains to central routes and vice versa. See below for more detail about the PreventAccessFromTenantDomains
middleware.
All tenant routes in your application should have the tenancy
middleware group applied on them.
The tenancy
middleware group marks the route as a tenant route. That middleware functions as a "flag" for the PreventAccessFromTenantDomains
, telling it that the route is a tenant route, since the middleware has no other way of distingushing central from tenant routes.
In previous versions, the InitializeTenancy
middleware was applied only on tenant routes. However, that lead to tenancy not being initialized in controller constructors, which could cause bugs. So from 2.1.0 on, tenancy is initialized on all routes on non-exempt domains, and if the route is not tenant, the request gets aborted by the PreventAccessFromTenantDomains
once Laravel reaches the route middleware step.
Central routes
Routes in files other than routes/tenant.php
will not have the tenancy
middleware automatically applied on them, so they will be central routes. If you want these routes to be tenant routes, you can apply the tenancy
middleware manually, as described in custom route groups below.
API routes / custom route groups
If you want certain routes (perhaps API routes) to be multi-tenant, wrap them in a Route group with this middleware:
Route::middleware('tenancy')->group(function () {
// Route::get('/', 'HelloWorld');
});
and make sure the Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains
middleware is applied on the entire group:
// app/Http/Kernel.php
protected $middlewareGroups = [
// ...
'api' => [
\Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains::class,
// ...
]
];
The PreventAccess...
middleware
The Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains
middleware prevents access to non-tenant routes from tenant domains by returning a redirect to the tenant app's home page (tenancy.home_url
). Conversely, it returns a 404 when a user attempts to visit a tenant route on a web (exempt) domain.
The tenancy:install
command applies this middleware to the web
and api
groups. To apply it for another route group, add this middleware manually to that group. You can do this in app/Http/Kernel.php
.
Conflicting routes
By default, you cannot have conflicting routes in web.php
and tenant.php
. It would break php artisan route:list
and route caching.
However, tenant routes are loaded after the web/api routes, so if you register your central routes only for domains listed in the tenancy.exempt_domains
config, you can use the same URLs for central and tenant routes.
Here's an example implementation:
// RouteServiceProvider
protected function mapWebRoutes()
{
foreach (config('tenancy.exempt_domains', []) as $domain) {
Route::middleware('web')
->domain($domain)
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
}
protected function mapApiRoutes()
{
foreach (config('tenancy.exempt_domains', []) as $domain) {
Route::prefix('api')
->middleware('api')
->domain($domain)
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
}
One thing to keep in mind though: If you use multiple exempt domains, you cannot use route names. They can be used only once, so the name would link to the URL on the first exempt domain.
If you don't need conflicting routes, you may want to do the following: Since you probably want cleaner URLs on your non-tenant part of the application (landing page, etc), prefix your tenant routes with something like /app
.