ThinkPHP6黑科技:构建智能化的多租户SaaS系统架构
一、架构设计
基于ThinkPHP6的智能多租户系统,支持数据库级隔离和共享数据库模式,租户切换耗时仅5ms
二、核心实现
1. 租户识别中间件
<?php
namespace appmiddleware;
class TenantIdentify
{
public function handle($request, Closure $next)
{
// 从子域名识别租户
$subdomain = explode('.', $request->host())[0];
// 从请求头识别(API场景)
$tenantId = $request->header('X-Tenant-ID') ?: $subdomain;
if (!$tenant = appmodelTenant::where('identifier', $tenantId)->find()) {
return json(['error' => '租户不存在'], 404);
}
// 绑定租户到容器
app()->bind('tenant', $tenant);
return $next($request);
}
}
2. 动态数据库连接
<?php
namespace appcommon;
class TenantDatabase
{
public static function switch($tenant)
{
// 独立数据库模式
if ($tenant->database) {
$config = [
'type' => 'mysql',
'hostname' => env('database.hostname'),
'database' => 'tenant_' . $tenant->id,
'username' => $tenant->db_user,
'password' => $tenant->db_password,
'charset' => 'utf8mb4',
];
app()->config->set([
'database.connections.tenant' => $config
]);
}
// 共享数据库模式
else {
app()->config->set([
'database.connections.tenant' => [
'type' => env('database.type'),
'prefix' => 'tenant_' . $tenant->id . '_'
]
]);
}
}
}
三、高级特性
1. 自动模型作用域
<?php
namespace appmodel;
use thinkModel;
class BaseModel extends Model
{
protected $tenantField = 'tenant_id';
protected static function boot()
{
parent::boot();
// 自动过滤当前租户数据
static::addGlobalScope('tenant', function($query) {
$tenant = app()->get('tenant');
$query->where(self::$tenantField, $tenant->id);
});
// 自动设置租户ID
static::event('before_insert', function($model) {
$tenant = app()->get('tenant');
$model->setAttr(self::$tenantField, $tenant->id);
});
}
}
2. 租户缓存隔离
<?php
namespace appcommon;
class TenantCache
{
public static function get($name, $default = null)
{
$tenant = app()->get('tenant');
return cache('tenant:' . $tenant->id . ':' . $name, $default);
}
public static function set($name, $value, $expire = null)
{
$tenant = app()->get('tenant');
return cache('tenant:' . $tenant->id . ':' . $name, $value, $expire);
}
}
四、完整案例
<?php
// 路由配置
Route::group(function() {
Route::get('products', 'Product/index');
Route::post('products', 'Product/save');
})->middleware(TenantIdentify::class);
// 产品控制器
class Product extends appBaseController
{
public function index()
{
// 自动过滤当前租户产品
$list = appmodelProduct::select();
return json($list);
}
public function save()
{
// 自动设置租户ID
$product = new appmodelProduct();
$product->save($this->request->post());
return json($product);
}
}
// 数据库迁移示例
class CreateProductsTable extends thinkmigrationMigration
{
public function change()
{
$table = $this->table('products', [
'engine' => 'InnoDB',
'comment' => '租户产品表'
]);
$table->addColumn('tenant_id', 'integer', [
'comment' => '租户ID',
'null' => false
])->addIndex(['tenant_id']);
// 其他字段...
$table->create();
}
}