mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 12:54:05 +00:00
[4.x] Cleanup (#1317)
* cleanup, resolve todos, add immediate todos * Improve path_identification_middleware docblock * rename leave() method in tests * wip fix hardcoded values making assumptions about the parameters used in routing * defaultParameterNames * fix CreatesDatabaseUsers return values * $tenant -> tenant() * resolve more todos * make comment block a complete block * Correct useTenantRoutesInFortify(), delete unused import * test fixes * remove todos * remove JobPipeline todo * simplify comment example * remove todo * fix VERSION_PREFIX in queue.yml --------- Co-authored-by: lukinovec <lukinovec@gmail.com>
This commit is contained in:
parent
eac88dcc2a
commit
657e165cc8
23 changed files with 148 additions and 182 deletions
|
|
@ -92,7 +92,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
|
|||
|
||||
protected function assetHelper(string|false $suffix): void
|
||||
{
|
||||
if (! $this->app['config']['tenancy.filesystem.asset_helper_tenancy']) {
|
||||
if (! $this->app['config']['tenancy.filesystem.asset_helper_override']) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,54 +7,52 @@ namespace Stancl\Tenancy\Bootstrappers\Integrations;
|
|||
use Illuminate\Config\Repository;
|
||||
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
|
||||
use Stancl\Tenancy\Contracts\Tenant;
|
||||
use Stancl\Tenancy\Enums\Context;
|
||||
use Stancl\Tenancy\Resolvers\PathTenantResolver;
|
||||
|
||||
/**
|
||||
* Allows customizing Fortify action redirects
|
||||
* so that they can also redirect to tenant routes instead of just the central routes.
|
||||
* Allows customizing Fortify action redirects so that they can also redirect
|
||||
* to tenant routes instead of just the central routes.
|
||||
*
|
||||
* Works with path and query string identification.
|
||||
* This should be used with path/query string identification OR when using Fortify
|
||||
* universally, including with domains.
|
||||
*
|
||||
* When using domain identification, there's no need to pass the tenant parameter,
|
||||
* you only want to customize the routes being used, so you can set $passTenantParameter
|
||||
* to false.
|
||||
*/
|
||||
class FortifyRouteBootstrapper implements TenancyBootstrapper
|
||||
{
|
||||
/**
|
||||
* Make Fortify actions redirect to custom routes.
|
||||
* Fortify redirects that should be used in tenant context.
|
||||
*
|
||||
* For each route redirect, specify the intended route context (central or tenant).
|
||||
* Based on the provided context, we pass the tenant parameter to the route (or not).
|
||||
* The tenant parameter is only passed to the route when you specify its context as tenant.
|
||||
*
|
||||
* The route redirects should be in the following format:
|
||||
*
|
||||
* 'fortify_action' => [
|
||||
* 'route_name' => 'tenant.route',
|
||||
* 'context' => Context::TENANT,
|
||||
* ]
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* FortifyRouteBootstrapper::$fortifyRedirectMap = [
|
||||
* // On logout, redirect the user to the "bye" route in the central app
|
||||
* 'logout' => [
|
||||
* 'route_name' => 'bye',
|
||||
* 'context' => Context::CENTRAL,
|
||||
* ],
|
||||
*
|
||||
* // On login, redirect the user to the "welcome" route in the tenant app
|
||||
* 'login' => [
|
||||
* 'route_name' => 'welcome',
|
||||
* 'context' => Context::TENANT,
|
||||
* ],
|
||||
* ];
|
||||
* Syntax: ['redirect_name' => 'tenant_route_name']
|
||||
*/
|
||||
public static array $fortifyRedirectMap = [];
|
||||
|
||||
/**
|
||||
* Should the tenant parameter be passed to fortify routes in the tenant context.
|
||||
*
|
||||
* This should be enabled with path/query string identification and disabled with domain identification.
|
||||
*
|
||||
* You may also disable this when using path/query string identification if passing the tenant parameter
|
||||
* is handled in another way (TenancyUrlGenerator::$passTenantParameter for both,
|
||||
* UrlGeneratorBootstrapper:$addTenantParameterToDefaults for path identification).
|
||||
*/
|
||||
public static bool $passTenantParameter = true;
|
||||
|
||||
/**
|
||||
* Tenant route that serves as Fortify's home (e.g. a tenant dashboard route).
|
||||
* This route will always receive the tenant parameter.
|
||||
*/
|
||||
public static string $fortifyHome = 'tenant.dashboard';
|
||||
public static string|null $fortifyHome = 'tenant.dashboard';
|
||||
|
||||
/**
|
||||
* Use default parameter names ('tenant' name and tenant key value) instead of the parameter name
|
||||
* and column name configured in the path resolver config.
|
||||
*
|
||||
* You want to enable this when using query string identification while having customized that config.
|
||||
*/
|
||||
public static bool $defaultParameterNames = false;
|
||||
|
||||
protected array $originalFortifyConfig = [];
|
||||
|
||||
|
|
@ -76,27 +74,22 @@ class FortifyRouteBootstrapper implements TenancyBootstrapper
|
|||
|
||||
protected function useTenantRoutesInFortify(Tenant $tenant): void
|
||||
{
|
||||
$tenantKey = $tenant->getTenantKey();
|
||||
$tenantParameterName = PathTenantResolver::tenantParameterName();
|
||||
$tenantParameterName = static::$defaultParameterNames ? 'tenant' : PathTenantResolver::tenantParameterName();
|
||||
$tenantParameterValue = static::$defaultParameterNames ? $tenant->getTenantKey() : PathTenantResolver::tenantParameterValue($tenant);
|
||||
|
||||
$generateLink = function (array $redirect) use ($tenantKey, $tenantParameterName) {
|
||||
// Specifying the context is only required with query string identification
|
||||
// because with path identification, the tenant parameter should always present
|
||||
$passTenantParameter = $redirect['context'] === Context::TENANT;
|
||||
|
||||
// Only pass the tenant parameter when the user should be redirected to a tenant route
|
||||
return route($redirect['route_name'], $passTenantParameter ? [$tenantParameterName => $tenantKey] : []);
|
||||
$generateLink = function (string $redirect) use ($tenantParameterValue, $tenantParameterName) {
|
||||
return route($redirect, static::$passTenantParameter ? [$tenantParameterName => $tenantParameterValue] : []);
|
||||
};
|
||||
|
||||
// Get redirect URLs for the configured redirect routes
|
||||
$redirects = array_merge(
|
||||
$this->originalFortifyConfig['redirects'] ?? [], // Fortify config redirects
|
||||
array_map(fn (array $redirect) => $generateLink($redirect), static::$fortifyRedirectMap), // Mapped redirects
|
||||
array_map(fn (string $redirect) => $generateLink($redirect), static::$fortifyRedirectMap), // Mapped redirects
|
||||
);
|
||||
|
||||
if (static::$fortifyHome) {
|
||||
// Generate the home route URL with the tenant parameter and make it the Fortify home route
|
||||
$this->config->set('fortify.home', route(static::$fortifyHome, [$tenantParameterName => $tenantKey]));
|
||||
$this->config->set('fortify.home', route(static::$fortifyHome, static::$passTenantParameter ? [$tenantParameterName => $tenantParameterValue] : []));
|
||||
}
|
||||
|
||||
$this->config->set('fortify.redirects', $redirects);
|
||||
|
|
|
|||
|
|
@ -36,13 +36,8 @@ class RootUrlBootstrapper implements TenancyBootstrapper
|
|||
protected string|null $originalRootUrl = null;
|
||||
|
||||
/**
|
||||
* You may want to selectively enable or disable this bootstrapper in specific tests.
|
||||
* For instance, when using `Livewire::test()` this bootstrapper can cause problems,
|
||||
* due to an internal Livewire route, so you may want to disable it, while in tests
|
||||
* that are generating URLs in things like mails, the bootstrapper should be used
|
||||
* just like in any queued job.
|
||||
*
|
||||
* todo@revisit
|
||||
* Overriding the root url may cause issues in *some* tests, so you can disable
|
||||
* the behavior by setting this property to false.
|
||||
*/
|
||||
public static bool $rootUrlOverrideInTests = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,10 @@ class UrlGeneratorBootstrapper implements TenancyBootstrapper
|
|||
if (static::$addTenantParameterToDefaults) {
|
||||
$defaultParameters = array_merge(
|
||||
$defaultParameters,
|
||||
[PathTenantResolver::tenantParameterName() => $tenant->getTenantKey()]
|
||||
[
|
||||
PathTenantResolver::tenantParameterName() => PathTenantResolver::tenantParameterValue($tenant), // path identification
|
||||
'tenant' => $tenant->getTenantKey(), // query string identification
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,16 +10,11 @@ trait CreatesDatabaseUsers
|
|||
{
|
||||
public function createDatabase(TenantWithDatabase $tenant): bool
|
||||
{
|
||||
parent::createDatabase($tenant);
|
||||
|
||||
return $this->createUser($tenant->database());
|
||||
return parent::createDatabase($tenant) && $this->createUser($tenant->database());
|
||||
}
|
||||
|
||||
public function deleteDatabase(TenantWithDatabase $tenant): bool
|
||||
{
|
||||
// Some DB engines require the user to be deleted before the database (e.g. Postgres)
|
||||
$this->deleteUser($tenant->database());
|
||||
|
||||
return parent::deleteDatabase($tenant);
|
||||
return $this->deleteUser($tenant->database()) && parent::deleteDatabase($tenant);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ use Stancl\Tenancy\Events\PullingPendingTenant;
|
|||
*/
|
||||
trait HasPending
|
||||
{
|
||||
public static string $pendingSinceCast = 'timestamp';
|
||||
|
||||
/** Boot the trait. */
|
||||
public static function bootHasPending(): void
|
||||
{
|
||||
|
|
@ -32,7 +34,7 @@ trait HasPending
|
|||
/** Initialize the trait. */
|
||||
public function initializeHasPending(): void
|
||||
{
|
||||
$this->casts['pending_since'] = 'timestamp';
|
||||
$this->casts['pending_since'] = static::$pendingSinceCast;
|
||||
}
|
||||
|
||||
/** Determine if the model instance is in a pending state. */
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ class MicrosoftSQLDatabaseManager extends TenantDatabaseManager
|
|||
public function createDatabase(TenantWithDatabase $tenant): bool
|
||||
{
|
||||
$database = $tenant->database()->getName();
|
||||
$charset = $this->connection()->getConfig('charset');
|
||||
$collation = $this->connection()->getConfig('collation'); // todo check why these are not used
|
||||
|
||||
return $this->connection()->statement("CREATE DATABASE [{$database}]");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ class PermissionControlledPostgreSQLSchemaManager extends PostgreSQLSchemaManage
|
|||
// Grant permissions to any existing tables. This is used with RLS
|
||||
// todo@samuel refactor this along with the todo in TenantDatabaseManager
|
||||
// and move the grantPermissions() call inside the condition in `ManagesPostgresUsers::createUser()`
|
||||
// but maybe moving it inside $createUser is wrong because some central user may migrate new tables
|
||||
// while the RLS user should STILL get access to those tables
|
||||
foreach ($tables as $table) {
|
||||
$tableName = $table->table_name;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,15 +7,11 @@ namespace Stancl\Tenancy\Events\Contracts;
|
|||
use Illuminate\Queue\SerializesModels;
|
||||
use Stancl\Tenancy\Contracts\Tenant;
|
||||
|
||||
abstract class TenantEvent // todo we could add a feature to JobPipeline that automatically gets data for the send() from here
|
||||
abstract class TenantEvent
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/** @var Tenant */
|
||||
public $tenant;
|
||||
|
||||
public function __construct(Tenant $tenant)
|
||||
{
|
||||
$this->tenant = $tenant;
|
||||
}
|
||||
public function __construct(
|
||||
public Tenant $tenant,
|
||||
) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
// todo perhaps create Identification namespace
|
||||
|
||||
namespace Stancl\Tenancy\Exceptions;
|
||||
|
||||
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class UserImpersonation implements Feature
|
|||
/**
|
||||
* Logout from the current domain and forget impersonation session.
|
||||
*/
|
||||
public static function leave(): void // todo@name possibly rename
|
||||
public static function stopImpersonating(): void
|
||||
{
|
||||
auth()->logout();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ use Illuminate\Routing\Events\RouteMatched;
|
|||
use Stancl\Tenancy\Enums\RouteMode;
|
||||
use Stancl\Tenancy\Resolvers\PathTenantResolver;
|
||||
|
||||
// todo@earlyIdReview
|
||||
|
||||
/**
|
||||
* Remove the tenant parameter from the matched route when path identification is used globally.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class PreventAccessFromUnwantedDomains
|
|||
return in_array($request->getHost(), config('tenancy.identification.central_domains'), true);
|
||||
}
|
||||
|
||||
// todo@samuel
|
||||
// todo@samuel technically not an identification middleware but probably ok to keep this here
|
||||
public function requestHasTenant(Request $request): bool
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ namespace Stancl\Tenancy\Overrides;
|
|||
|
||||
use Illuminate\Cache\CacheManager as BaseCacheManager;
|
||||
|
||||
// todo@move move to Cache namespace?
|
||||
|
||||
class CacheManager extends BaseCacheManager
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -85,6 +85,14 @@ class TenancyUrlGenerator extends UrlGenerator
|
|||
*/
|
||||
public static array $overrides = [];
|
||||
|
||||
/**
|
||||
* Use default parameter names ('tenant' name and tenant key value) instead of the parameter name
|
||||
* and column name configured in the path resolver config.
|
||||
*
|
||||
* You want to enable this when using query string identification while having customized that config.
|
||||
*/
|
||||
public static bool $defaultParameterNames = false;
|
||||
|
||||
/**
|
||||
* Override the route() method so that the route name gets prefixed
|
||||
* and the tenant parameter gets added when in tenant context.
|
||||
|
|
@ -166,7 +174,15 @@ class TenancyUrlGenerator extends UrlGenerator
|
|||
*/
|
||||
protected function addTenantParameter(array $parameters): array
|
||||
{
|
||||
return tenant() && static::$passTenantParameterToRoutes ? array_merge($parameters, [PathTenantResolver::tenantParameterName() => tenant()->getTenantKey()]) : $parameters;
|
||||
if (tenant() && static::$passTenantParameterToRoutes) {
|
||||
if (static::$defaultParameterNames) {
|
||||
return array_merge($parameters, ['tenant' => tenant()->getTenantKey()]);
|
||||
} else {
|
||||
return array_merge($parameters, [PathTenantResolver::tenantParameterName() => PathTenantResolver::tenantParameterValue(tenant())]);
|
||||
}
|
||||
} else {
|
||||
return $parameters;
|
||||
}
|
||||
}
|
||||
|
||||
protected function routeNameOverride(string $name): string|null
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class PathTenantResolver extends Contracts\CachedTenantResolver
|
|||
|
||||
public static function tenantRouteNamePrefix(): string
|
||||
{
|
||||
return config('tenancy.identification.resolvers.' . static::class . '.tenant_route_name_prefix') ?? static::tenantParameterName() . '.';
|
||||
return config('tenancy.identification.resolvers.' . static::class . '.tenant_route_name_prefix') ?? 'tenant.';
|
||||
}
|
||||
|
||||
public static function tenantModelColumn(): string
|
||||
|
|
@ -81,6 +81,11 @@ class PathTenantResolver extends Contracts\CachedTenantResolver
|
|||
return config('tenancy.identification.resolvers.' . static::class . '.tenant_model_column') ?? tenancy()->model()->getTenantKeyName();
|
||||
}
|
||||
|
||||
public static function tenantParameterValue(Tenant $tenant): string
|
||||
{
|
||||
return $tenant->getAttribute(static::tenantModelColumn());
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public static function allowedExtraModelColumns(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ use Illuminate\Database\Eloquent\Model;
|
|||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
|
||||
|
||||
// todo@move move all resource syncing-related things to a separate namespace?
|
||||
|
||||
/**
|
||||
* @property-read TenantWithDatabase[]|Collection<int, TenantWithDatabase&Model> $tenants
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue