mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-05 04:34:03 +00:00
request data identification: add tenant_model_column configuration
This commit is contained in:
parent
16171b1eaa
commit
ec9b585e70
5 changed files with 61 additions and 20 deletions
|
|
@ -132,6 +132,8 @@ return [
|
||||||
'cookie' => 'tenant',
|
'cookie' => 'tenant',
|
||||||
'query_parameter' => 'tenant',
|
'query_parameter' => 'tenant',
|
||||||
|
|
||||||
|
'tenant_model_column' => null, // null = tenant key
|
||||||
|
|
||||||
'cache' => false,
|
'cache' => false,
|
||||||
'cache_ttl' => 3600, // seconds
|
'cache_ttl' => 3600, // seconds
|
||||||
'cache_store' => null, // null = default
|
'cache_store' => null, // null = default
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,7 @@ class TenancyUrlGenerator extends UrlGenerator
|
||||||
{
|
{
|
||||||
if (tenant() && static::$passTenantParameterToRoutes) {
|
if (tenant() && static::$passTenantParameterToRoutes) {
|
||||||
if (static::$defaultParameterNames) {
|
if (static::$defaultParameterNames) {
|
||||||
|
// todo0 this should be changed to something like static::$queryParameter and it should respect the configured tenant model column
|
||||||
return array_merge($parameters, ['tenant' => tenant()->getTenantKey()]);
|
return array_merge($parameters, ['tenant' => tenant()->getTenantKey()]);
|
||||||
} else {
|
} else {
|
||||||
return array_merge($parameters, [PathTenantResolver::tenantParameterName() => PathTenantResolver::tenantParameterValue(tenant())]);
|
return array_merge($parameters, [PathTenantResolver::tenantParameterName() => PathTenantResolver::tenantParameterValue(tenant())]);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ class RequestDataTenantResolver extends Contracts\CachedTenantResolver
|
||||||
{
|
{
|
||||||
$payload = (string) $args[0];
|
$payload = (string) $args[0];
|
||||||
|
|
||||||
if ($payload && $tenant = tenancy()->find($payload, withRelations: true)) {
|
$column = static::tenantModelColumn();
|
||||||
|
|
||||||
|
if ($payload && $tenant = tenancy()->find($payload, $column, withRelations: true)) {
|
||||||
return $tenant;
|
return $tenant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,6 +36,11 @@ class RequestDataTenantResolver extends Contracts\CachedTenantResolver
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function tenantModelColumn(): string
|
||||||
|
{
|
||||||
|
return config('tenancy.identification.resolvers.' . static::class . '.tenant_model_column') ?? tenancy()->model()->getTenantKeyName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the header used for identification, or null if header identification is disabled.
|
* Returns the name of the header used for identification, or null if header identification is disabled.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ test('request data identification route helper behavior', function (bool $addTen
|
||||||
|
|
||||||
tenancy()->initialize($tenant);
|
tenancy()->initialize($tenant);
|
||||||
|
|
||||||
// todo0 test changing tenancy.identification.resolvers.<request data>.query_parameter
|
// todo0 test changing tenancy.identification.resolvers.<request data>.query_parameter and tenant_model_column
|
||||||
|
|
||||||
if ($passTenantParameterToRoutes) {
|
if ($passTenantParameterToRoutes) {
|
||||||
expect(route('tenant.home'))->toBe("{$appUrl}/tenant/home?tenant={$tenantKey}");
|
expect(route('tenant.home'))->toBe("{$appUrl}/tenant/home?tenant={$tenantKey}");
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByRequestDataException;
|
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByRequestDataException;
|
||||||
use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData;
|
use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData;
|
||||||
|
|
@ -21,50 +22,80 @@ beforeEach(function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('header identification works', function () {
|
test('header identification works', function (string|null $tenantModelColumn) {
|
||||||
$tenant = Tenant::create();
|
if ($tenantModelColumn) {
|
||||||
|
Schema::table('tenants', function (Blueprint $table) use ($tenantModelColumn) {
|
||||||
|
$table->string($tenantModelColumn)->unique();
|
||||||
|
});
|
||||||
|
Tenant::$extraCustomColumns = [$tenantModelColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.tenant_model_column' => $tenantModelColumn]);
|
||||||
|
|
||||||
|
$tenant = Tenant::create($tenantModelColumn ? [$tenantModelColumn => 'acme'] : []);
|
||||||
|
$payload = $tenantModelColumn ? 'acme' : $tenant->id;
|
||||||
|
|
||||||
// Default header name
|
// Default header name
|
||||||
$this->withoutExceptionHandling()->withHeader('X-Tenant', $tenant->id)->get('test')->assertSee($tenant->id);
|
$this->withoutExceptionHandling()->withHeader('X-Tenant', $payload)->get('test')->assertSee($tenant->id);
|
||||||
|
|
||||||
// Custom header name
|
// Custom header name
|
||||||
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.header' => 'X-Custom-Tenant']);
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.header' => 'X-Custom-Tenant']);
|
||||||
$this->withoutExceptionHandling()->withHeader('X-Custom-Tenant', $tenant->id)->get('test')->assertSee($tenant->id);
|
$this->withoutExceptionHandling()->withHeader('X-Custom-Tenant', $payload)->get('test')->assertSee($tenant->id);
|
||||||
|
|
||||||
// Setting the header to null disables header identification
|
// Setting the header to null disables header identification
|
||||||
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.header' => null]);
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.header' => null]);
|
||||||
expect(fn () => $this->withoutExceptionHandling()->withHeader('X-Tenant', $tenant->id)->get('test'))->toThrow(TenantCouldNotBeIdentifiedByRequestDataException::class);
|
expect(fn () => $this->withoutExceptionHandling()->withHeader('X-Tenant', $payload)->get('test'))->toThrow(TenantCouldNotBeIdentifiedByRequestDataException::class);
|
||||||
});
|
})->with([null, 'slug']);
|
||||||
|
|
||||||
test('query parameter identification works', function () {
|
test('query parameter identification works', function (string|null $tenantModelColumn) {
|
||||||
$tenant = Tenant::create();
|
if ($tenantModelColumn) {
|
||||||
|
Schema::table('tenants', function (Blueprint $table) use ($tenantModelColumn) {
|
||||||
|
$table->string($tenantModelColumn)->unique();
|
||||||
|
});
|
||||||
|
Tenant::$extraCustomColumns = [$tenantModelColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.tenant_model_column' => $tenantModelColumn]);
|
||||||
|
|
||||||
|
$tenant = Tenant::create($tenantModelColumn ? [$tenantModelColumn => 'acme'] : []);
|
||||||
|
$payload = $tenantModelColumn ? 'acme' : $tenant->id;
|
||||||
|
|
||||||
// Default query parameter name
|
// Default query parameter name
|
||||||
$this->withoutExceptionHandling()->get('test?tenant=' . $tenant->id)->assertSee($tenant->id);
|
$this->withoutExceptionHandling()->get('test?tenant=' . $payload)->assertSee($tenant->id);
|
||||||
|
|
||||||
// Custom query parameter name
|
// Custom query parameter name
|
||||||
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.query_parameter' => 'custom_tenant']);
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.query_parameter' => 'custom_tenant']);
|
||||||
$this->withoutExceptionHandling()->get('test?custom_tenant=' . $tenant->id)->assertSee($tenant->id);
|
$this->withoutExceptionHandling()->get('test?custom_tenant=' . $payload)->assertSee($tenant->id);
|
||||||
|
|
||||||
// Setting the query parameter to null disables query parameter identification
|
// Setting the query parameter to null disables query parameter identification
|
||||||
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.query_parameter' => null]);
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.query_parameter' => null]);
|
||||||
expect(fn () => $this->withoutExceptionHandling()->get('test?tenant=' . $tenant->id))->toThrow(TenantCouldNotBeIdentifiedByRequestDataException::class);
|
expect(fn () => $this->withoutExceptionHandling()->get('test?tenant=' . $payload))->toThrow(TenantCouldNotBeIdentifiedByRequestDataException::class);
|
||||||
});
|
})->with([null, 'slug']);
|
||||||
|
|
||||||
test('cookie identification works', function () {
|
test('cookie identification works', function (string|null $tenantModelColumn) {
|
||||||
$tenant = Tenant::create();
|
if ($tenantModelColumn) {
|
||||||
|
Schema::table('tenants', function (Blueprint $table) use ($tenantModelColumn) {
|
||||||
|
$table->string($tenantModelColumn)->unique();
|
||||||
|
});
|
||||||
|
Tenant::$extraCustomColumns = [$tenantModelColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.tenant_model_column' => $tenantModelColumn]);
|
||||||
|
|
||||||
|
$tenant = Tenant::create($tenantModelColumn ? [$tenantModelColumn => 'acme'] : []);
|
||||||
|
$payload = $tenantModelColumn ? 'acme' : $tenant->id;
|
||||||
|
|
||||||
// Default cookie name
|
// Default cookie name
|
||||||
$this->withoutExceptionHandling()->withUnencryptedCookie('tenant', $tenant->id)->get('test')->assertSee($tenant->id);
|
$this->withoutExceptionHandling()->withUnencryptedCookie('tenant', $payload)->get('test')->assertSee($tenant->id);
|
||||||
|
|
||||||
// Custom cookie name
|
// Custom cookie name
|
||||||
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.cookie' => 'custom_tenant_id']);
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.cookie' => 'custom_tenant_id']);
|
||||||
$this->withoutExceptionHandling()->withUnencryptedCookie('custom_tenant_id', $tenant->id)->get('test')->assertSee($tenant->id);
|
$this->withoutExceptionHandling()->withUnencryptedCookie('custom_tenant_id', $payload)->get('test')->assertSee($tenant->id);
|
||||||
|
|
||||||
// Setting the cookie to null disables cookie identification
|
// Setting the cookie to null disables cookie identification
|
||||||
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.cookie' => null]);
|
config(['tenancy.identification.resolvers.' . RequestDataTenantResolver::class . '.cookie' => null]);
|
||||||
expect(fn () => $this->withoutExceptionHandling()->withUnencryptedCookie('tenant', $tenant->id)->get('test'))->toThrow(TenantCouldNotBeIdentifiedByRequestDataException::class);
|
expect(fn () => $this->withoutExceptionHandling()->withUnencryptedCookie('tenant', $payload)->get('test'))->toThrow(TenantCouldNotBeIdentifiedByRequestDataException::class);
|
||||||
});
|
})->with([null, 'slug']);
|
||||||
|
|
||||||
// todo@tests encrypted cookie
|
// todo@tests encrypted cookie
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue