Skip to content

UrlGeneratorBootstrapper

The UrlGeneratorBootstrapper overrides the default UrlGenerator with our own TenancyUrlGenerator which supports context-aware route generation. In other words, it makes generating URLs easier in the tenant context, especially with path identification or third-party package integrations.

If this bootstrapper is enabled, it will override the default UrlGenerator with TenancyUrlGenerator as mentioned above. In addition to that, it has one configurable static property:

UrlGeneratorBootstrapper::$addTenantParameterToDefaults = true;

If this property is set to true, the URL generator override will add:

'tenant' => tenant()->getTenantKey(),

to URL::defaults(). That is a URL generator feature which sets default parameter values, in other words if you have a route with a {tenant} parameter and you set a default value for the tenant parameter, you can generate the route as route('foo') instead of route('foo', ['tenant' => tenant('id')]). This is in line with how the rest of the package tries to minimize code changes across application code (and especially useful with third-party package integrations as mentioned above).

Note that the default value isn’t literally the above. Instead, it follows this config:

config/tenancy.php
'resolvers' => [
// ...
Resolvers\PathTenantResolver::class => [
'tenant_parameter_name' => 'tenant',
'tenant_model_column' => null, // null = tenant key
'tenant_route_name_prefix' => 'tenant.',
'allowed_extra_model_columns' => [], // used with binding route fields
'cache' => false,
'cache_ttl' => 3600, // seconds
'cache_store' => null, // null = default
],
// ...

In other words, with this config:

'tenant_parameter_name' => 'team',
'tenant_model_column' => 'slug',

The parameter would be set as:

'team' => tenant()->slug,

In addition to setting a default value for the tenant_parameter_name, the bootstrapper also sets defaults for all extra model columns whitelisted in allowed_extra_model_columns, also in the config above. For instance this config:

'tenant_parameter_name' => 'team',
'tenant_model_column' => null,
'allowed_extra_model_columns' => ['slug'],

Would set the following default values:

'team' => tenant()->getTenantKey(),
'team:slug' => tenant()->slug,

Which would also support routes with binding fields, i.e.:

Route::get('/{team:slug}/foo', ...)->name('tenant.foo');
// these would work the same:
route('tenant.foo');
route('tenant.foo', ['team' => tenant()->slug]);

The TenancyUrlGenerator class provides further configuration options:

TenancyUrlGenerator:$prefixRouteNames = false;

The $prefixRouteNames static property tells the URL generator override whether route names should be prefixed with tenant. (the actual prefix name comes from PathTenantResolver::tenantRouteNamePrefix() — see the config discussed above).

In other words, if you are in the tenant context, route generation works like this:

route('foo'); // becomes route('tenant.foo')
route('tenant.foo'); // no change as the route name already starts with the tenant prefix
TenancyUrlGenerator:$passTenantParameterToRoutes = false;

The $passTenantParameterToRoutes static property tells the URL generator override whether the tenant parameter (again name comes from PathTenantResolver::tenantParameterName()) should be passed to the route parameters. This is typically not needed if URL defaults are already used, but you may prefer that the parameter is passed directly instead of depending on URL defaults, if URL defaults don’t work for your use case for some reason.

TenancyUrlGenerator:$passQueryParameter = false;

The $passQueryParameter static property tells the URL generator override to pass a query parameter instead of the tenant parameter mentioned above to the routes. This option requires that $passTenantParameterToRoutes is enabled. This setting changes the passed parameter to instead be RequestDataTenantResolver::queryParameterName(), with a value of RequestDataTenantResolver::payloadValue(tenant()), instead of PathTenantResolver::tenantParameterName(). The use case is query parameter identification with the InitializeTenancyByRequestData middleware.

See the relevant configuration:

config/tenancy.php
Resolvers\RequestDataTenantResolver::class => [
// Set any of these to null to disable that method of identification
'header' => 'X-Tenant',
'cookie' => 'tenant',
'query_parameter' => 'tenant',
'tenant_model_column' => null, // null = tenant key
'cache' => false,
'cache_ttl' => 3600, // seconds
'cache_store' => null, // null = default
],

You may also want to take a look at the methods mentioned above directly.

TenancyUrlGenerator::$overrides = [];

The $overrides static property tells the URL generator override to replace some routes with other routes in the tenant context. The typical use case is that you’d want to keep $prefixRouteNames disabled, and instead only pass a small set of routes to be replaced to this array. This can be helpful if you only have a handful of routes that have a tenant variant, that existing (including third-party package) code, should use instead of the existing central route calls, but you also have many central route calls that you don’t want to have to add the bypass parameter to.

TenancyUrlGenerator::$bypassParameter = 'central';

The $bypassParameter static property lets you customize the name of the bypass parameter, i.e. the parameter that can be used to “escape” the tenant scoping and generate a route as if you were currently in the central context. In other words, overrides are ignored, route names are not prefixed, and the tenant parameter or query parameter is not passed.

It’s common for path identification setups to have clones of some central routes, often authentication routes, with shared code in the central and tenant context that simply references e.g. route('auth.login'). You’d want this to become route('tenant.login') in the tenant context, with the tenant parameter automatically passed in.

In such a setup, you’d enable the bootstrapper and use the following configuration:

UrlGeneratorBootstrapper::$addTenantParameterToDefaults = true;
// or
TenancyUrlGenerator:$passTenantParameterToRoutes = true;
TenancyUrlGenerator:$prefixRouteNames = true;

It’s generally recommended to use $addTenantParameterToDefaults only — if your use case is supported — instead of $passTenantParameterToRoutes as it’s a bit less invasive. URL defaults are also supported by Ziggy.