1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 18:44:03 +00:00

Cloning: addTenantMiddleware() for specifying ID MW for cloned route

Previously, tenant identification middleware was typically specified
for the cloned route by "inheriting" it from the central route, which
necessarily meant that the central route had to also be marked as
universal so it could continue working in the central context --
despite presumably not being usable in the tenant context, thus being
universal for no proper reason. In such cases, universal routes were
used mainly as a mechanism for specifying the tenant identification
middleware to use on the cloned tenant route.

Given that recent refactors of the cloning feature have made it more
customizable and a bit nicer to use "multiple times", i.e. run handle()
with a few different configurations of the action, letting the
developer specify the used tenant middleware using a method like this
only makes sense.

The feature also becomes more independently usable and not just a
"hack for universal routes with path identification".
This commit is contained in:
Samuel Štancl 2025-11-08 18:39:28 +01:00
parent 97c5afd2cf
commit 197513dd84
No known key found for this signature in database
GPG key ID: BA146259A1E16C57
2 changed files with 43 additions and 3 deletions

View file

@ -30,6 +30,8 @@ use Stancl\Tenancy\Resolvers\PathTenantResolver;
* By providing a callback to shouldClone(), you can change how it's determined if a route should be cloned if you don't want to use middleware flags.
*
* Cloned routes are prefixed with '/{tenant}', flagged with 'tenant' middleware, and have their names prefixed with 'tenant.'.
* The addition of the 'tenant' middleware can be controlled using addTenantMiddleware(array). You can specify the identification
* middleware to be used on the cloned route using that method -- instead of using the approach that "inherits" it from a universal route.
*
* The addition of the tenant parameter can be controlled using addTenantParameter(true|false). Note that if you decide to disable
* tenant parameter addition, the routes MUST differ in domains. This can be controlled using the domain(string|null) method. The
@ -91,6 +93,7 @@ class CloneRoutesAsTenant
protected Closure|null $cloneUsing = null; // The callback should accept Route instance or the route name (string)
protected Closure|null $shouldClone = null;
protected array $cloneRoutesWithMiddleware = ['clone'];
protected array $addTenantMiddleware = ['tenant'];
public function __construct(
protected Router $router,
@ -148,6 +151,18 @@ class CloneRoutesAsTenant
return $this;
}
/**
* The tenant middleware to be added to the cloned route.
*
* If used with early identification, make sure to include 'tenant' in this array.
*/
public function addTenantMiddleware(array $middleware): static
{
$this->addTenantMiddleware = $middleware;
return $this;
}
/** The domain the cloned route should use. Set to null if it shouldn't be scoped to a domain. */
public function domain(string|null $domain): static
{
@ -271,9 +286,7 @@ class CloneRoutesAsTenant
fn ($mw) => ! in_array($mw, $this->cloneRoutesWithMiddleware) && ! in_array($mw, ['central', 'tenant', 'universal'])
);
$processedMiddleware[] = 'tenant';
return array_unique($processedMiddleware);
return array_unique(array_merge($processedMiddleware, $this->addTenantMiddleware));
}
/** Check if route already has tenant parameter or name prefix. */

View file

@ -437,3 +437,30 @@ test('cloning a route without a prefix or differing domains overrides the origin
expect(collect(RouteFacade::getRoutes()->get())->map->getName())->toContain('tenant.foo');
expect(collect(RouteFacade::getRoutes()->get())->map->getName())->not()->toContain('foo');
});
test('addTenantMiddleware can be used to specify the tenant middleware for the cloned route', function () {
RouteFacade::get('/foo', fn () => true)->name('foo')->middleware(['clone']);
RouteFacade::get('/bar', fn () => true)->name('bar')->middleware(['clone']);
$cloneAction = app(CloneRoutesAsTenant::class);
$cloneAction->cloneRoute('foo')->addTenantMiddleware([InitializeTenancyByPath::class])->handle();
expect(collect(RouteFacade::getRoutes()->get())->map->getName())->toContain('tenant.foo');
$cloned = RouteFacade::getRoutes()->getByName('tenant.foo');
expect($cloned->uri())->toBe('{tenant}/foo');
expect($cloned->getName())->toBe('tenant.foo');
expect(tenancy()->getRouteMiddleware($cloned))->toBe([InitializeTenancyByPath::class]);
$cloneAction->cloneRoute('bar')
->addTenantMiddleware([InitializeTenancyByDomain::class])
->domain('foo.localhost')
->addTenantParameter(false)
->tenantParameterBeforePrefix(false)
->handle();
expect(collect(RouteFacade::getRoutes()->get())->map->getName())->toContain('tenant.bar');
$cloned = RouteFacade::getRoutes()->getByName('tenant.bar');
expect($cloned->uri())->toBe('bar');
expect($cloned->getName())->toBe('tenant.bar');
expect($cloned->getDomain())->toBe('foo.localhost');
expect(tenancy()->getRouteMiddleware($cloned))->toBe([InitializeTenancyByDomain::class]);
});