Laravel:如何用Model Trait实现单库多租户的数据自动过滤与填充
单数据库多租户架构实现方案
一、自动为所有查询添加租户ID条件
通过Laravel的全局作用域可以实现自动给模型的所有查询追加tenant_id条件,步骤如下:
- 创建租户全局作用域类
<?php namespace App\Scopes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; use Illuminate\Support\Facades\Auth; class TenantScope implements Scope { public function apply(Builder $builder, Model $model) { // 仅在用户已登录时添加租户条件,避免命令行或未登录场景报错 if (Auth::check()) { $builder->where('tenant_id', Auth::user()->tenant_id); } } }
- 让需要租户隔离的模型继承统一基类
创建一个BaseModel,所有需要租户隔离的业务模型都继承它:
<?php namespace App\Models; use App\Scopes\TenantScope; use Illuminate\Database\Eloquent\Model; class BaseModel extends Model { protected static function boot() { parent::boot(); // 注册租户全局作用域 static::addGlobalScope(new TenantScope); } }
比如你的订单、商品模型可以这样写:
class Order extends BaseModel { // 模型其他逻辑 }
- 临时跳过租户隔离(可选)
如果需要超级管理员查看全量数据,用withoutGlobalScope方法跳过:
// 查询所有租户的订单 $allOrders = Order::withoutGlobalScope(TenantScope::class)->get();
二、创建模型时自动填充租户ID
通过模型的creating事件自动赋值tenant_id,在基类中统一实现即可:
修改BaseModel的boot方法,添加创建事件监听:
protected static function boot() { parent::boot(); static::addGlobalScope(new TenantScope); // 创建模型时自动填充tenant_id static::creating(function ($model) { if (Auth::check()) { $model->tenant_id = Auth::user()->tenant_id; } }); }
这样调用Order::create($data)时,tenant_id会自动填充当前登录用户的租户ID,无需手动传入。
如果需要更灵活的控制(比如部分模型不需要自动填充),也可以单独创建观察者类:
<?php namespace App\Observers; use Illuminate\Support\Facades\Auth; class TenantObserver { public function creating($model) { if (Auth::check()) { $model->tenant_id = Auth::user()->tenant_id; } } }
然后在AppServiceProvider的boot方法中注册观察者:
public function boot() { \App\Models\Order::observe(\App\Observers\TenantObserver::class); \App\Models\Product::observe(\App\Observers\TenantObserver::class); }
内容的提问来源于stack exchange,提问作者tcgkn
相关产品推荐
相关产品推荐

