1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-03-21 23:44:03 +00:00

[4.x] Make URL::temporarySignedRoute() respect the bypass parameter (#1438)

Using `URL::temporarySignedRoute()` in tenant context with
`UrlGeneratorBootstrapper` enabled doesn't work the same as `route()`.
The bypass parameter doesn't actually bypass the route name prefixing.

`route()` is called in the `parent::temporarySignedRoute()` call, and
because the bypass parameter is removed before calling
`parent::temporarySignedRoute()`, the underlying `route()` call doesn't
get the bypass parameter and it ends up attempting to generate URL for a
route with the name prefixed with 'tenant.'.

This PR adds the bypass parameter back after `prepareRouteInputs()`, so
that `parent::temporarySignedRoute()` receives it, and the underlying
`route()` call respects it. Also added basic tests for the
`URL::temporarySignedRoute()` behavior (the new bypass parameter test
works as a regression test).
This commit is contained in:
lukinovec 2026-03-09 02:07:02 +01:00 committed by GitHub
parent 37b2a91aa9
commit 16861d2599
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 1 deletions

View file

@ -129,7 +129,15 @@ class TenancyUrlGenerator extends UrlGenerator
throw new InvalidArgumentException('Attribute [name] expects a string backed enum.');
}
[$name, $parameters] = $this->prepareRouteInputs($name, Arr::wrap($parameters)); // @phpstan-ignore argument.type
$wrappedParameters = Arr::wrap($parameters);
[$name, $parameters] = $this->prepareRouteInputs($name, $wrappedParameters); // @phpstan-ignore argument.type
if (isset($wrappedParameters[static::$bypassParameter])) {
// If the bypass parameter was passed, we need to add it back to the parameters after prepareRouteInputs() removes it,
// so that the underlying route() call in parent::temporarySignedRoute() can bypass the behavior modification as well.
$parameters[static::$bypassParameter] = $wrappedParameters[static::$bypassParameter];
}
return parent::temporarySignedRoute($name, $expiration, $parameters, $absolute);
}

View file

@ -2,6 +2,7 @@
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\URL;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
@ -25,12 +26,16 @@ beforeEach(function () {
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
TenancyUrlGenerator::$prefixRouteNames = false;
TenancyUrlGenerator::$passTenantParameterToRoutes = false;
TenancyUrlGenerator::$overrides = [];
TenancyUrlGenerator::$bypassParameter = 'central';
UrlGeneratorBootstrapper::$addTenantParameterToDefaults = false;
});
afterEach(function () {
TenancyUrlGenerator::$prefixRouteNames = false;
TenancyUrlGenerator::$passTenantParameterToRoutes = false;
TenancyUrlGenerator::$overrides = [];
TenancyUrlGenerator::$bypassParameter = 'central';
UrlGeneratorBootstrapper::$addTenantParameterToDefaults = false;
});
@ -359,3 +364,40 @@ test('both the name prefixing and the tenant parameter logic gets skipped when b
expect(route('home', ['bypassParameter' => false, 'tenant' => $tenant->getTenantKey()]))->toBe($tenantRouteUrl)
->not()->toContain('bypassParameter');
});
test('the temporarySignedRoute method can automatically prefix the passed route name', function() {
config(['tenancy.bootstrappers' => [UrlGeneratorBootstrapper::class]]);
Route::get('/{tenant}/foo', fn () => 'foo')->name('tenant.foo')->middleware([InitializeTenancyByPath::class]);
TenancyUrlGenerator::$prefixRouteNames = true;
$tenant = Tenant::create();
tenancy()->initialize($tenant);
// Route name ('foo') gets prefixed automatically (will be 'tenant.foo')
$tenantSignedUrl = URL::temporarySignedRoute('foo', now()->addMinutes(2), ['tenant' => $tenantKey = $tenant->getTenantKey()]);
expect($tenantSignedUrl)->toContain("localhost/{$tenantKey}/foo");
});
test('the bypass parameter works correctly with temporarySignedRoute', function() {
config(['tenancy.bootstrappers' => [UrlGeneratorBootstrapper::class]]);
Route::get('/foo', fn () => 'foo')->name('central.foo');
TenancyUrlGenerator::$prefixRouteNames = true;
TenancyUrlGenerator::$bypassParameter = 'central';
$tenant = Tenant::create();
tenancy()->initialize($tenant);
// Bypass parameter allows us to generate URL for the 'central.foo' route in tenant context
$centralSignedUrl = URL::temporarySignedRoute('central.foo', now()->addMinutes(2), ['central' => true]);
expect($centralSignedUrl)
->toContain('localhost/foo')
->not()->toContain('central='); // Bypass parameter gets removed from the generated URL
});