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

Simplify TenantWithDatabase interface, move tenantConfig() logic

This commit is contained in:
Samuel Štancl 2024-03-01 10:48:33 +01:00
parent 8a269f8dd8
commit e8c3c75d7c
5 changed files with 68 additions and 59 deletions

View file

@ -40,10 +40,6 @@ parameters:
message: '#Illuminate\\Routing\\UrlGenerator#' message: '#Illuminate\\Routing\\UrlGenerator#'
paths: paths:
- src/Bootstrappers/FilesystemTenancyBootstrapper.php - src/Bootstrappers/FilesystemTenancyBootstrapper.php
-
message: '#Trying to invoke Closure\|null but it might not be a callable#'
paths:
- src/Database/DatabaseConfig.php
- -
message: '#Unable to resolve the template type (TMapWithKeysKey|TMapWithKeysValue) in call to method#' message: '#Unable to resolve the template type (TMapWithKeysKey|TMapWithKeysValue) in call to method#'
paths: paths:

View file

@ -4,15 +4,38 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Database\Concerns; namespace Stancl\Tenancy\Database\Concerns;
use Illuminate\Database\Eloquent\Model;
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase; use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Database\DatabaseConfig; use Stancl\Tenancy\Database\DatabaseConfig;
/**
* @mixin Model
*/
trait HasDatabase trait HasDatabase
{ {
use HasInternalKeys;
public function database(): DatabaseConfig public function database(): DatabaseConfig
{ {
/** @var TenantWithDatabase $this */ /** @var TenantWithDatabase&Model $this */
$databaseConfig = [];
return new DatabaseConfig($this); foreach ($this->getAttributes() as $key => $value) {
if (str($key)->startsWith($this->internalPrefix() . 'db_')) {
if ($key === $this->internalPrefix() . 'db_name') {
// Remove DB name because we set that separately
continue;
}
if ($key === $this->internalPrefix() . 'db_connection') {
// Remove DB connection because that's not used here
continue;
}
$databaseConfig[str($key)->after($this->internalPrefix() . 'db_')->toString()] = $value;
}
}
return new DatabaseConfig($this, $databaseConfig);
} }
} }

View file

@ -4,6 +4,9 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Database\Concerns; namespace Stancl\Tenancy\Database\Concerns;
/**
* @mixin \Illuminate\Database\Eloquent\Model
*/
trait HasInternalKeys trait HasInternalKeys
{ {
/** Get the internal prefix. */ /** Get the internal prefix. */

View file

@ -11,13 +11,4 @@ interface TenantWithDatabase extends Tenant
{ {
/** Get the tenant's database config. */ /** Get the tenant's database config. */
public function database(): DatabaseConfig; public function database(): DatabaseConfig;
/** Get the internal prefix. */
public static function internalPrefix(): string;
/** Get an internal key. */
public function getInternal(string $key): mixed;
/** Set internal key. */
public function setInternal(string $key, mixed $value): static;
} }

View file

@ -18,35 +18,57 @@ class DatabaseConfig
/** The tenant whose database we're dealing with. */ /** The tenant whose database we're dealing with. */
public Tenant&Model $tenant; public Tenant&Model $tenant;
/** Database username generator (can be set by the developer.) */ /** Additional config for the database connection, specific to this tenant. */
public static Closure|null $usernameGenerator = null; public array $tenantConfig;
/** Database password generator (can be set by the developer.) */ /**
public static Closure|null $passwordGenerator = null; * Database username generator (can be set by the developer.).
*
* @var Closure(Model&Tenant): string
*/
public static Closure $usernameGenerator;
/** Database name generator (can be set by the developer.) */ /**
public static Closure|null $databaseNameGenerator = null; * Database password generator (can be set by the developer.).
*
* @var Closure(Model&Tenant): string
*/
public static Closure $passwordGenerator;
/**
* Database name generator (can be set by the developer.).
*
* @var Closure(Model&Tenant): string
*/
public static Closure $databaseNameGenerator;
public static function __constructStatic(): void public static function __constructStatic(): void
{ {
static::$usernameGenerator = static::$usernameGenerator ?? function (Model&Tenant $tenant) { if (! isset(static::$usernameGenerator)) {
static::$usernameGenerator = function () {
return Str::random(16); return Str::random(16);
}; };
static::$passwordGenerator = static::$passwordGenerator ?? function (Model&Tenant $tenant) {
return Hash::make(Str::random(32));
};
static::$databaseNameGenerator = static::$databaseNameGenerator ?? function (Model&Tenant $tenant) {
return config('tenancy.database.prefix') . $tenant->getTenantKey() . config('tenancy.database.suffix');
};
} }
public function __construct(Model&Tenant $tenant) if (! isset(static::$passwordGenerator)) {
static::$passwordGenerator = function () {
return Hash::make(Str::random(32));
};
}
if (! isset(static::$databaseNameGenerator)) {
static::$databaseNameGenerator = function (Model&Tenant $tenant) {
return config('tenancy.database.prefix') . $tenant->getTenantKey() . config('tenancy.database.suffix');
};
}
}
public function __construct(Model&Tenant $tenant, array $databaseConfig)
{ {
static::__constructStatic(); static::__constructStatic();
$this->tenant = $tenant; $this->tenant = $tenant;
$this->tenantConfig = $databaseConfig;
} }
public static function generateDatabaseNamesUsing(Closure $databaseNameGenerator): void public static function generateDatabaseNamesUsing(Closure $databaseNameGenerator): void
@ -134,7 +156,7 @@ class DatabaseConfig
$templateConnection = $this->getTemplateConnection(); $templateConnection = $this->getTemplateConnection();
return $this->manager()->makeConnectionConfig( return $this->manager()->makeConnectionConfig(
array_merge($templateConnection, $this->tenantConfig()), array_merge($templateConnection, $this->tenantConfig),
$this->getName() $this->getName()
); );
} }
@ -144,7 +166,7 @@ class DatabaseConfig
*/ */
public function hostConnection(): array public function hostConnection(): array
{ {
$config = $this->tenantConfig(); $config = $this->tenantConfig;
$templateConnection = $this->getTemplateConnection(); $templateConnection = $this->getTemplateConnection();
if ($this->connectionDriverManager($this->getTemplateConnectionDriver()) instanceof Contracts\ManagesDatabaseUsers) { if ($this->connectionDriverManager($this->getTemplateConnectionDriver()) instanceof Contracts\ManagesDatabaseUsers) {
@ -169,32 +191,6 @@ class DatabaseConfig
DB::purge($this->getTenantHostConnectionName()); DB::purge($this->getTenantHostConnectionName());
} }
/**
* Additional config for the database connection, specific to this tenant.
*/
public function tenantConfig(): array
{
$dbConfig = array_filter(array_keys($this->tenant->getAttributes()), function ($key) {
return Str::startsWith($key, $this->tenant->internalPrefix() . 'db_');
});
// Remove DB name because we set that separately
if (($pos = array_search($this->tenant->internalPrefix() . 'db_name', $dbConfig)) !== false) {
unset($dbConfig[$pos]);
}
// Remove DB connection because that's not used inside the array
if (($pos = array_search($this->tenant->internalPrefix() . 'db_connection', $dbConfig)) !== false) {
unset($dbConfig[$pos]);
}
return array_reduce($dbConfig, function ($config, $key) {
return array_merge($config, [
Str::substr($key, strlen($this->tenant->internalPrefix() . 'db_')) => $this->tenant->getAttribute($key),
]);
}, []);
}
/** Get the TenantDatabaseManager for this tenant's connection. /** Get the TenantDatabaseManager for this tenant's connection.
* *
* @throws NoConnectionSetException|DatabaseManagerNotRegisteredException * @throws NoConnectionSetException|DatabaseManagerNotRegisteredException