mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-14 07:54:04 +00:00
Allow defining the tenant connection template using array syntax in config (#1040)
* `template_tenant_connection` can be array or string * Update TenantDatabaseManagerTest.php * Update TenantDatabaseManagerTest.php * Update TenantDatabaseManagerTest.php * Update DatabaseConfig.php * partial database config for template * Update tests/TenantDatabaseManagerTest.php Co-authored-by: lukinovec <lukinovec@gmail.com> * update test name * improve test names * add comments --------- Co-authored-by: lukinovec <lukinovec@gmail.com> Co-authored-by: Samuel Štancl <samuel@archte.ch>
This commit is contained in:
parent
342c67fe02
commit
087733d5db
2 changed files with 103 additions and 14 deletions
|
|
@ -87,7 +87,7 @@ class DatabaseConfig
|
||||||
{
|
{
|
||||||
$this->tenant->setInternal('db_name', $this->getName());
|
$this->tenant->setInternal('db_name', $this->getName());
|
||||||
|
|
||||||
if ($this->connectionDriverManager($this->getTemplateConnectionName()) instanceof Contracts\ManagesDatabaseUsers) {
|
if ($this->connectionDriverManager($this->getTemplateConnectionDriver()) instanceof Contracts\ManagesDatabaseUsers) {
|
||||||
$this->tenant->setInternal('db_username', $this->getUsername() ?? (static::$usernameGenerator)($this->tenant));
|
$this->tenant->setInternal('db_username', $this->getUsername() ?? (static::$usernameGenerator)($this->tenant));
|
||||||
$this->tenant->setInternal('db_password', $this->getPassword() ?? (static::$passwordGenerator)($this->tenant));
|
$this->tenant->setInternal('db_password', $this->getPassword() ?? (static::$passwordGenerator)($this->tenant));
|
||||||
}
|
}
|
||||||
|
|
@ -97,11 +97,29 @@ class DatabaseConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTemplateConnectionName(): string
|
public function getTemplateConnectionDriver(): string
|
||||||
{
|
{
|
||||||
return $this->tenant->getInternal('db_connection')
|
return $this->getTemplateConnection()['driver'];
|
||||||
?? config('tenancy.database.template_tenant_connection')
|
}
|
||||||
?? config('tenancy.database.central_connection');
|
|
||||||
|
public function getTemplateConnection(): array
|
||||||
|
{
|
||||||
|
if ($template = $this->tenant->getInternal('db_connection')) {
|
||||||
|
return config("database.connections.{$template}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($template = config('tenancy.database.template_tenant_connection')) {
|
||||||
|
return is_array($template) ? array_merge($this->getCentralConnection(), $template) : config("database.connections.{$template}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getCentralConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCentralConnection(): array
|
||||||
|
{
|
||||||
|
$centralConnectionName = config('tenancy.database.central_connection');
|
||||||
|
|
||||||
|
return config("database.connections.{$centralConnectionName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTenantHostConnectionName(): string
|
public function getTenantHostConnectionName(): string
|
||||||
|
|
@ -114,8 +132,7 @@ class DatabaseConfig
|
||||||
*/
|
*/
|
||||||
public function connection(): array
|
public function connection(): array
|
||||||
{
|
{
|
||||||
$template = $this->getTemplateConnectionName();
|
$templateConnection = $this->getTemplateConnection();
|
||||||
$templateConnection = config("database.connections.{$template}");
|
|
||||||
|
|
||||||
return $this->manager()->makeConnectionConfig(
|
return $this->manager()->makeConnectionConfig(
|
||||||
array_merge($templateConnection, $this->tenantConfig()),
|
array_merge($templateConnection, $this->tenantConfig()),
|
||||||
|
|
@ -129,10 +146,9 @@ class DatabaseConfig
|
||||||
public function hostConnection(): array
|
public function hostConnection(): array
|
||||||
{
|
{
|
||||||
$config = $this->tenantConfig();
|
$config = $this->tenantConfig();
|
||||||
$template = $this->getTemplateConnectionName();
|
$templateConnection = $this->getTemplateConnection();
|
||||||
$templateConnection = config("database.connections.{$template}");
|
|
||||||
|
|
||||||
if ($this->connectionDriverManager($template) instanceof Contracts\ManagesDatabaseUsers) {
|
if ($this->connectionDriverManager($this->getTemplateConnectionDriver()) instanceof Contracts\ManagesDatabaseUsers) {
|
||||||
// We're removing the username and password because user with these credentials is not created yet
|
// We're removing the username and password because user with these credentials is not created yet
|
||||||
// If you need to provide username and password when using PermissionControlledMySQLDatabaseManager,
|
// If you need to provide username and password when using PermissionControlledMySQLDatabaseManager,
|
||||||
// consider creating a new connection and use it as `tenancy_db_connection` tenant config key
|
// consider creating a new connection and use it as `tenancy_db_connection` tenant config key
|
||||||
|
|
@ -196,7 +212,7 @@ class DatabaseConfig
|
||||||
$tenantHostConnectionName = $this->getTenantHostConnectionName();
|
$tenantHostConnectionName = $this->getTenantHostConnectionName();
|
||||||
config(["database.connections.{$tenantHostConnectionName}" => $this->hostConnection()]);
|
config(["database.connections.{$tenantHostConnectionName}" => $this->hostConnection()]);
|
||||||
|
|
||||||
$manager = $this->connectionDriverManager($tenantHostConnectionName);
|
$manager = $this->connectionDriverManager(config("database.connections.{$tenantHostConnectionName}.driver"));
|
||||||
|
|
||||||
if ($manager instanceof Contracts\StatefulTenantDatabaseManager) {
|
if ($manager instanceof Contracts\StatefulTenantDatabaseManager) {
|
||||||
$manager->setConnection($tenantHostConnectionName);
|
$manager->setConnection($tenantHostConnectionName);
|
||||||
|
|
@ -211,10 +227,8 @@ class DatabaseConfig
|
||||||
*
|
*
|
||||||
* @throws DatabaseManagerNotRegisteredException
|
* @throws DatabaseManagerNotRegisteredException
|
||||||
*/
|
*/
|
||||||
protected function connectionDriverManager(string $connectionName): Contracts\TenantDatabaseManager
|
protected function connectionDriverManager(string $driver): Contracts\TenantDatabaseManager
|
||||||
{
|
{
|
||||||
$driver = config("database.connections.{$connectionName}.driver");
|
|
||||||
|
|
||||||
$databaseManagers = config('tenancy.database.managers');
|
$databaseManagers = config('tenancy.database.managers');
|
||||||
|
|
||||||
if (! array_key_exists($driver, $databaseManagers)) {
|
if (! array_key_exists($driver, $databaseManagers)) {
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,81 @@ test('path used by sqlite manager can be customized', function () {
|
||||||
expect(file_exists($customPath . '/' . $name))->toBeTrue();
|
expect(file_exists($customPath . '/' . $name))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the tenant connection template can be specified either by name or as a connection array', function () {
|
||||||
|
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||||
|
return $event->tenant;
|
||||||
|
})->toListener());
|
||||||
|
|
||||||
|
config([
|
||||||
|
'tenancy.database.managers.mysql' => MySQLDatabaseManager::class,
|
||||||
|
'tenancy.database.template_tenant_connection' => 'mysql',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$name = 'foo' . Str::random(8);
|
||||||
|
$tenant = Tenant::create([
|
||||||
|
'tenancy_db_name' => $name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/** @var MySQLDatabaseManager $manager */
|
||||||
|
$manager = $tenant->database()->manager();
|
||||||
|
expect($manager->databaseExists($name))->toBeTrue();
|
||||||
|
expect($manager->database()->getConfig('host'))->toBe('mysql');
|
||||||
|
|
||||||
|
config([
|
||||||
|
'tenancy.database.template_tenant_connection' => [
|
||||||
|
'driver' => 'mysql',
|
||||||
|
'url' => null,
|
||||||
|
'host' => 'mysql2',
|
||||||
|
'port' => '3306',
|
||||||
|
'database' => 'main',
|
||||||
|
'username' => 'root',
|
||||||
|
'password' => 'password',
|
||||||
|
'unix_socket' => '',
|
||||||
|
'charset' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => true,
|
||||||
|
'engine' => null,
|
||||||
|
'options' => [],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tenant = Tenant::create([
|
||||||
|
'tenancy_db_name' => $name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/** @var MySQLDatabaseManager $manager */
|
||||||
|
$manager = $tenant->database()->manager();
|
||||||
|
expect($manager->databaseExists($name))->toBeTrue(); // tenant connection works
|
||||||
|
expect($manager->database()->getConfig('host'))->toBe('mysql2');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('partial tenant connection templates get merged into the central connection template', function () {
|
||||||
|
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||||
|
return $event->tenant;
|
||||||
|
})->toListener());
|
||||||
|
|
||||||
|
config([
|
||||||
|
'database.connections.central.url' => 'example.com',
|
||||||
|
'tenancy.database.template_tenant_connection' => [
|
||||||
|
'url' => null,
|
||||||
|
'host' => 'mysql2',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$name = 'foo' . Str::random(8);
|
||||||
|
$tenant = Tenant::create([
|
||||||
|
'tenancy_db_name' => $name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/** @var MySQLDatabaseManager $manager */
|
||||||
|
$manager = $tenant->database()->manager();
|
||||||
|
expect($manager->databaseExists($name))->toBeTrue(); // tenant connection works
|
||||||
|
expect($manager->database()->getConfig('host'))->toBe('mysql2');
|
||||||
|
expect($manager->database()->getConfig('url'))->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
// Datasets
|
// Datasets
|
||||||
dataset('database_managers', [
|
dataset('database_managers', [
|
||||||
['mysql', MySQLDatabaseManager::class],
|
['mysql', MySQLDatabaseManager::class],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue