1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 14:34:04 +00:00

Add tenant parameter BEFORE existing prefixes by default, add tenantParameterBeforePrefix() to allow customizing this (#1393)

This commit is contained in:
lukinovec 2025-09-03 15:56:12 +02:00 committed by GitHub
parent 364637dc23
commit d983bf9547
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 13 deletions

View file

@ -86,6 +86,7 @@ class CloneRoutesAsTenant
{ {
protected array $routesToClone = []; protected array $routesToClone = [];
protected bool $addTenantParameter = true; protected bool $addTenantParameter = true;
protected bool $tenantParameterBeforePrefix = true;
protected string|null $domain = null; protected string|null $domain = null;
protected Closure|null $cloneUsing = null; // The callback should accept Route instance or the route name (string) protected Closure|null $cloneUsing = null; // The callback should accept Route instance or the route name (string)
protected Closure|null $shouldClone = null; protected Closure|null $shouldClone = null;
@ -177,6 +178,13 @@ class CloneRoutesAsTenant
return $this; return $this;
} }
public function tenantParameterBeforePrefix(bool $tenantParameterBeforePrefix): static
{
$this->tenantParameterBeforePrefix = $tenantParameterBeforePrefix;
return $this;
}
/** Clone an individual route. */ /** Clone an individual route. */
public function cloneRoute(Route|string $route): static public function cloneRoute(Route|string $route): static
{ {
@ -226,7 +234,13 @@ class CloneRoutesAsTenant
$action->put('middleware', $middleware); $action->put('middleware', $middleware);
if ($this->addTenantParameter) { if ($this->addTenantParameter) {
$action->put('prefix', $prefix . '/{' . PathTenantResolver::tenantParameterName() . '}'); $tenantParameter = '{' . PathTenantResolver::tenantParameterName() . '}';
$newPrefix = $this->tenantParameterBeforePrefix
? $tenantParameter . '/' . $prefix
: $prefix . '/' . $tenantParameter;
$action->put('prefix', $newPrefix);
} }
/** @var Route $newRoute */ /** @var Route $newRoute */

View file

@ -172,7 +172,7 @@ test('the clone action can clone specific routes either using name or route inst
false, false,
]); ]);
test('the clone action prefixes already prefixed routes correctly', function () { test('the clone action prefixes already prefixed routes correctly', function (bool $tenantParameterBeforePrefix) {
$routes = [ $routes = [
RouteFacade::get('/home', fn () => true) RouteFacade::get('/home', fn () => true)
->middleware(['clone']) ->middleware(['clone'])
@ -195,7 +195,12 @@ test('the clone action prefixes already prefixed routes correctly', function ()
->prefix('prefix/'), ->prefix('prefix/'),
]; ];
app(CloneRoutesAsTenant::class)->handle(); $cloneAction = app(CloneRoutesAsTenant::class);
$cloneAction
->tenantParameterBeforePrefix($tenantParameterBeforePrefix)
->handle();
$expectedPrefix = $tenantParameterBeforePrefix ? '{tenant}/prefix' : 'prefix/{tenant}';
$clonedRoutes = [ $clonedRoutes = [
RouteFacade::getRoutes()->getByName('tenant.home'), RouteFacade::getRoutes()->getByName('tenant.home'),
@ -206,9 +211,10 @@ test('the clone action prefixes already prefixed routes correctly', function ()
// The cloned route is prefixed correctly // The cloned route is prefixed correctly
foreach ($clonedRoutes as $key => $route) { foreach ($clonedRoutes as $key => $route) {
expect($route->getPrefix())->toBe("prefix/{tenant}"); expect($route->getPrefix())->toBe($expectedPrefix);
$clonedRouteUrl = route($route->getName(), ['tenant' => $tenant = Tenant::create()]); $clonedRouteUrl = route($route->getName(), ['tenant' => $tenant = Tenant::create()]);
$expectedPrefixInUrl = $tenantParameterBeforePrefix ? "{$tenant->id}/prefix" : "prefix/{$tenant->id}";
expect($clonedRouteUrl) expect($clonedRouteUrl)
// Original prefix does not occur in the cloned route's URL // Original prefix does not occur in the cloned route's URL
@ -216,14 +222,14 @@ test('the clone action prefixes already prefixed routes correctly', function ()
->not()->toContain("//prefix") ->not()->toContain("//prefix")
->not()->toContain("prefix//") ->not()->toContain("prefix//")
// Instead, the route is prefixed correctly // Instead, the route is prefixed correctly
->toBe("http://localhost/prefix/{$tenant->id}/{$routes[$key]->getName()}"); ->toBe("http://localhost/{$expectedPrefixInUrl}/{$routes[$key]->getName()}");
// The cloned route is accessible // The cloned route is accessible
pest()->get($clonedRouteUrl)->assertOk(); pest()->get($clonedRouteUrl)->assertOk();
} }
}); })->with([true, false]);
test('clone action trims trailing slashes from prefixes given to nested route groups', function () { test('clone action trims trailing slashes from prefixes given to nested route groups', function (bool $tenantParameterBeforePrefix) {
RouteFacade::prefix('prefix')->group(function () { RouteFacade::prefix('prefix')->group(function () {
RouteFacade::prefix('')->group(function () { RouteFacade::prefix('')->group(function () {
// This issue seems to only happen when there's a group with a prefix, then a group with an empty prefix, and then a / route // This issue seems to only happen when there's a group with a prefix, then a group with an empty prefix, and then a / route
@ -237,7 +243,10 @@ test('clone action trims trailing slashes from prefixes given to nested route gr
}); });
}); });
app(CloneRoutesAsTenant::class)->handle(); $cloneAction = app(CloneRoutesAsTenant::class);
$cloneAction
->tenantParameterBeforePrefix($tenantParameterBeforePrefix)
->handle();
$clonedLandingUrl = route('tenant.landing', ['tenant' => $tenant = Tenant::create()]); $clonedLandingUrl = route('tenant.landing', ['tenant' => $tenant = Tenant::create()]);
$clonedHomeRouteUrl = route('tenant.home', ['tenant' => $tenant]); $clonedHomeRouteUrl = route('tenant.home', ['tenant' => $tenant]);
@ -245,17 +254,20 @@ test('clone action trims trailing slashes from prefixes given to nested route gr
$landingRoute = RouteFacade::getRoutes()->getByName('tenant.landing'); $landingRoute = RouteFacade::getRoutes()->getByName('tenant.landing');
$homeRoute = RouteFacade::getRoutes()->getByName('tenant.home'); $homeRoute = RouteFacade::getRoutes()->getByName('tenant.home');
expect($landingRoute->uri())->toBe('prefix/{tenant}'); $expectedPrefix = $tenantParameterBeforePrefix ? '{tenant}/prefix' : 'prefix/{tenant}';
expect($homeRoute->uri())->toBe('prefix/{tenant}/home'); $expectedPrefixInUrl = $tenantParameterBeforePrefix ? "{$tenant->id}/prefix" : "prefix/{$tenant->id}";
expect($landingRoute->uri())->toBe($expectedPrefix);
expect($homeRoute->uri())->toBe("{$expectedPrefix}/home");
expect($clonedLandingUrl) expect($clonedLandingUrl)
->not()->toContain("prefix//") ->not()->toContain("prefix//")
->toBe("http://localhost/prefix/{$tenant->id}"); ->toBe("http://localhost/{$expectedPrefixInUrl}");
expect($clonedHomeRouteUrl) expect($clonedHomeRouteUrl)
->not()->toContain("prefix//") ->not()->toContain("prefix//")
->toBe("http://localhost/prefix/{$tenant->id}/home"); ->toBe("http://localhost/{$expectedPrefixInUrl}/home");
}); })->with([true, false]);
test('tenant routes are ignored from cloning and clone middleware in groups causes no issues', function () { test('tenant routes are ignored from cloning and clone middleware in groups causes no issues', function () {
// Should NOT be cloned, already has tenant parameter // Should NOT be cloned, already has tenant parameter