Laravel-5和Multitenancy数据库设置

时间:2015-08-02 08:30:08

标签: php laravel laravel-5 eloquent

我开始开发SaaS应用程序,并且已经创建了我的数据库结构。我打算创建一个中间件文件来处理该请求的数据库连接。在这个中间件文件中,我想创建一个模型,它总是只选择与当前连接cust_id(外键)对应的任何表中的行。

例如:

$Customers->where('cust_id', $cust_id)->first();

如何在不必在每个select语句中指定where('cust_id', $cust_id)的情况下执行此操作?

1 个答案:

答案 0 :(得分:2)

您可以使用模型中的 Eloquent全局查询范围轻松实现这一目标。您可以在此处详细了解它们:http://laravel.com/docs/5.1/eloquent#query-scopes

首先,您需要定义多租户范围类,它将更新所有运行的查询并在 cust_id 字段上添加约束:

class MultitenantScope implements ScopeInterface
{
  public function apply(Builder $builder, Model $model)
  {
    if (Auth::id()) {
      $builder->whereCustId(Auth::id()); 
    } else {
      $model = $builder->getModel();
      // apply a constraint that will never be true
      // so that no records are fetched for unauthorized users
      $builder->whereNull($model->getKeyName()); 
    }
 }

  public function remove(Builder $builder, Model $model)
  {
    $query = $builder->getQuery();
    $query->wheres = collect($query->wheres)->reject(function ($where) {
      return ($where['column'] == 'cust_id');
    })->values()->all();
  }  
}

然后您需要一个特征,您将添加到需要过滤的模型中:

trait MultitenantTrait
{
  public static function bootMultitenantTrait()
  {
    static::addGlobalScope(new MultitenantScope());
  }

  public static function allTenants()
  {
    return (new static())->newQueryWithoutScope(new MultitenantScope());
  }
}

最后一部分是将 MultitenantTrait 添加到您的模型中:

class SomeModel extends Eloquent {
  use MultitenantTrait;
}

现在,每次使用Eloquent的模型方法进行任何查询时, cust_id 约束都将应用于查询,并且只有属于给定 cust_id 将可用。

如果由于某种原因您需要访问所有对象,则可以使用 allTenants()方法运行查询而不需要额外的约束:

$allRows = SomeModel::allTenants()->get();

请注意,我还没有测试过这些确切的代码,如果您发现任何问题,请告诉我们,我们非常乐意为您提供相应的服务:)