1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-06 15:24:03 +00:00

Handle MySQL charset and collation

Make createDatabase execute CREATE DATABASE without passing charset and collation so that if these parameters are null, the MySQL server's defaults will be used. Only add charset and collation to the statement if they're not null.
This commit is contained in:
lukinovec 2026-05-04 11:15:51 +02:00
parent ea20eb13b6
commit 405aaafb4e
2 changed files with 85 additions and 1 deletions

View file

@ -16,7 +16,21 @@ class MySQLDatabaseManager extends TenantDatabaseManager
$this->validateParameter([$database, $charset, $collation]);
return $this->connection()->statement("CREATE DATABASE `{$database}` CHARACTER SET `$charset` COLLATE `$collation`");
// MySQL defaults to the server's charset and collation
// if charset and collation are not specified.
// If charset is specified but collation is null, MySQL
// will choose a default collation for the specified charset (and vice versa).
$statement = "CREATE DATABASE `{$database}`";
if ($charset !== null) {
$statement .= " CHARACTER SET `{$charset}`";
}
if ($collation !== null) {
$statement .= " COLLATE `{$collation}`";
}
return $this->connection()->statement($statement);
}
public function deleteDatabase(TenantWithDatabase $tenant): bool

View file

@ -661,6 +661,76 @@ test('sqlite database manager respects the configured path while making the data
expect($tenant->database()->connection()['database'])->toBe($customPath . 'tenant.sqlite');
});
test('newly created tenant databases use the correct charset and collation with mysql', function () {
config([
'tenancy.bootstrappers' => [DatabaseTenancyBootstrapper::class],
]);
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
return $event->tenant;
})->toListener());
withBootstrapping();
$charset = fn () => DB::selectOne('SELECT DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = DATABASE()')->DEFAULT_CHARACTER_SET_NAME;
$collation = fn () => DB::selectOne('SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = DATABASE()')->DEFAULT_COLLATION_NAME;
$defaultTenant = Tenant::create();
tenancy()->initialize($defaultTenant);
// No charset or collation specified,
// defaults from the MySQL config used.
expect($charset())->toBe('utf8mb4');
expect($collation())->toBe('utf8mb4_unicode_ci');
$tenantWithCharsetAndCollation = Tenant::create([
'tenancy_db_charset' => 'latin1',
'tenancy_db_collation' => 'latin1_swedish_ci',
]);
tenancy()->initialize($tenantWithCharsetAndCollation);
// Custom charset and collation from tenant config
expect($charset())->toBe('latin1');
expect($collation())->toBe('latin1_swedish_ci');
$tenantWithNullCharsetAndCollation = Tenant::create([
'tenancy_db_charset' => null,
'tenancy_db_collation' => null,
]);
tenancy()->initialize($tenantWithNullCharsetAndCollation);
// Default MySQL server charset and collation
expect($charset())->toBe('utf8mb4');
expect($collation())->toBe('utf8mb4_0900_ai_ci');
$tenantWithCharsetAndNullCollation = Tenant::create([
'tenancy_db_charset' => 'binary',
'tenancy_db_collation' => null,
]);
tenancy()->initialize($tenantWithCharsetAndNullCollation);
// Charset specified, collation is null,
// MySQL will choose a default collation for the specified charset.
expect($charset())->toBe('binary');
expect($collation())->toBe('binary');
// Collation specified, charset is null,
// MySQL will choose a default charset for the specified collation.
$tenantWithCollationAndNullCharset = Tenant::create([
'tenancy_db_charset' => null,
'tenancy_db_collation' => 'latin1_swedish_ci',
]);
tenancy()->initialize($tenantWithCollationAndNullCharset);
expect($charset())->toBe('latin1');
expect($collation())->toBe('latin1_swedish_ci');
});
// Datasets
dataset('database_managers', [
['mysql', MySQLDatabaseManager::class],