globecode / laravel-multitenant
Laravel 多租户
Requires
- php: >=5.4.0
- illuminate/support: 4.2.*
This package is not auto-updated.
Last update: 2024-09-24 03:08:08 UTC
README
2014年9月29日:作为L4包发布的WIP。
安装
-
在您的
composer.json
文件中的"require"
块中要求此包。"globecode/laravel-multitenant": "dev-master"
-
将服务提供者添加到
app/config/app.php
文件中的 providers 数组。这仅用于下面两步中的 "发布config
" 命令'GlobeCode\LaravelMultiTenant\LaravelMultiTenantServiceProvider'
-
进入您的项目目录,并通过 Composer 进行更新
composer update
-
将
config
发布到您的应用程序中。这允许您更改您模式中 租户 列的名称。一个config
文件将被安装到app/config/packages/globecode/laravel-multitenant/
,您可以编辑它php artisan config:publish globecode/laravel-multitenant
-
创建并运行新的 migrations 以设置必要的模式。示例迁移在包
migrations
文件夹中提供。 -
将
getTenantId()
方法添加到您的User
(以及任何其他 "受限" 模型)或只添加到一次BaseModel
(推荐)/** * Get the value to scope the "tenant id" with. * * @return string */ public function getTenantId() { return (isset($this->tenant_id)) ? $this->tenant_id : null; }
-
可选的 全局覆盖。如果您想全局覆盖范围,例如对 管理员,则将
isAdmin()
方法添加到您的User
模型中。如果此方法返回true
,则ScopedByTenant
特性将查找此方法并自动覆盖所有查询的范围/** * Does the current user have an 'admin' role? * * @return bool */ public function isAdmin() { // Change to return true using whatever // roles/permissions you use in your app. return $this->hasRole('admin'); }
用法
-
使用
ScopedByTenant
特性对模型进行范围限定,使该模型上的所有查询全局限定于一个租户。永远不用担心意外查询到租户数据之外的数据!<?php namespace Acme; use GlobeCode\LaravelMultiTenant\ScopedByTenant; class Example { /** * Only this line is required. The extra below is just * for example on what a relation might look like. */ use ScopedByTenant; protected $table = 'example'; /** * Query the Tenant the Example belongs to. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function tenant() { return $this->belongsTo('Acme\Tenant'); } }
-
全局移除范围
A:全局 移除 从 控制器(例如在 管理员 情况下)的范围
<?php use GlobeCode\LaravelMultiTenant\ScopedByTenant; class AdminExamplesController { /** * @var Acme\Repositories\ExampleRepository */ protected $exampleRepo; public function __construct(ExampleRepository $exampleRepo) { $this->exampleRepo = $exampleRepo; // All queries in this controller on 'exampleRepo' // will be 'global' and not scoped. $this->exampleRepo->removeTenant(); } /** * Display a listing of all Examples. * * @return Response */ public function index() { // Global, will *not* be scoped. $leads = $this->exampleRepo->getAll(); $this->view('examples.index', compact('examples')); } }
或者
B:通过在
ScopedByTenant
特性的bootTenantId()
方法中使用Auth
检查来全局 移除 范围。请参阅上面 设置 -> 可选全局覆盖 部分的说明。
注意:您可以在模型和控制器中使用 ScopedByTenant
特性的任何 public
方法。
存储库
如果您使用存储库,则需要使用 TenantScope
类而不是 ScopedByTenant
特性来构建查询。如果您查看 TenantScope
类,您会看到有对 \Illuminate\Database\Query\Builder 的扩展,这些是您的存储库可用的方法;特性在存储库中不起作用。
以下是一个包含所有必要方法的示例 Eloquent 存储库。这些方法应放在一个 EloquentBaseRepository
类中,以保持代码的DRY。
<?php namespace Acme\Repositories; use Illuminate\Database\Eloquent\Model; use Acme\Example; use Acme\Repositories\ExampleRepository class EloquentExampleRepository extends ExampleRepository { /** * @var Example */ protected $model; /** * Method extensions from TenantScope class */ protected $whereTenant; protected $applyTenant; protected $removeTenant; public function __construct(Example $model) { $this->model = $model; $this->whereTenant = null; $this->applyTenant = null; $this->removeTenant = false; } /** * Example get all using scope. */ public function getAll() { return $this->getQueryBuilder()->get(); } /** * Example get by id using scope. */ public function getById($id) { return $this->getQueryBuilder()->find((int) $id); } /** * Limit scope to specific Tenant * Local method on repo, not on TenantScope. * * @param integer $id */ public function whereTenant($id) { $this->whereTenant = $id; return $this; } /** * Remove Tenant scope. */ public function removeTenant() { $this->removeTenant = true; return $this; } /** * Limit scope to specific Tenant(s) * * @param int|array $arg */ public function applyTenant($arg) { $this->applyTenant = $arg; return $this; } /** * Expand scope to all Tenants. */ public function allTenants() { return $this->removeTenant(); } protected function getQualifiedTenantColumn() { $tenantColumn = Config::get('laravel-multitenant::tenant_column'); return $this->model->getTable() .'.'. $tenantColumn; } /** * Returns a Builder instance for use in constructing * a query, honoring the current filters. Resets the * filters, ready for the next query. * * Example usage: * $result = $this->getQueryBuilder()->find($id); * * @return \Illuminate\Database\Query\Builder */ protected function getQueryBuilder() { $modelClass = $this->model; $builder = with(new $modelClass)->newQuery(); if ( ! is_null($this->whereTenant)) $builder->where($this->getQualifiedTenantColumn(), $this->whereTenant); if ($this->applyTenant) $builder->applyTenant($this->applyTenant); if ($this->removeTenant) $builder->removeTenant(); $this->whereTenant = null; $this->applyTenant = null; $this->removeTenant = null; return $builder; } }
播种
您可以在播种文件中手动覆盖范围,以避免难以查找关系,通过手动设置 覆盖
<?php use Acme\User; use GlobeCode\LaravelMultiTenant\TenantScope; class UsersTableSeeder extends DatabaseSeeder { public function run() { // Manually override tenant scoping. TenantScope::setOverride(); User::create([ 'id' => 1, 'tenant_id' => null, // an admin 'email' => 'admin@us.com', 'password' => 'secret', 'created_at' => time(), 'updated_at' => time() ]); User::create([ 'id' => 2, 'tenant_id' => 1000, // a tenant 'email' => 'user@tenant.com', 'password' => 'secret', 'created_at' => time(), 'updated_at' => time() ]); ... } }
注意:将 tenant_id
字段(或您选择的任何范围列名称)设置为 null
以避免任何内部人员/管理员。
关于
概念:从 AuraEQ Laravel Multi Tenant 中硬分叉。非常感谢他的初始工作。
Packagist: globecode/laravel-multitenant
推特: @jhaurawachsman
版权(c)2014 Jhaura Wachsman
在MIT许可下。