nunomazer/laravel-samehouse

一个基于单数据库的多租户Laravel包,简单易用

1.3.0 2024-04-17 01:51 UTC

This package is auto-updated.

Last update: 2024-09-22 01:26:55 UTC


README

Latest Version on Packagist Build Status Total Downloads Software License

laravel-samehouse

适用于 Laravel & Lumen 5.2+

适用于 Laravel & Lumen 版本 5.2 - 11 的单数据库多租户包。

注意:此包基于 HipsterJazzbo/Landlord 和 Torzer/awesome-landlord。 此版本是从已被归档的 https://github.com/torzer/awesome-landlord 分支出来的。

安装

要开始,请引入此包

composer require nunomazer/laravel-samehouse

Laravel

config/app.php 中添加 ServiceProvider

    'providers' => [
        ...
        NunoMazer\Samehouse\LandlordServiceProvider::class,
    ],

如果需要,注册 Facade

    'aliases' => [
        ...
        'Landlord'   => NunoMazer\Samehouse\Facades\Landlord::class,
    ],

您还可以发布配置文件

php artisan vendor:publish --provider="NunoMazer\Samehouse\LandlordServiceProvider"

并设置您的 default_tenant_columns 设置,如果您有全局默认值。LandLord 将使用此设置来范围没有设置 $tenantColumns 属性的模型。

Lumen

您需要在 bootstrap/app.php 中设置服务提供者

$app->register(NunoMazer\Samehouse\LandlordServiceProvider::class);

并确保您已经取消注释了 $app->withEloquent()

用法

此包假设您在所有租户范围表中至少有一个列引用了每行属于哪个租户。

例如,您可能有一个 companies 表,以及一些其他表,这些表都有一个 company_id 列。

添加和删除租户

重要提示: Landlord 是无状态的。这意味着当您调用 addTenant() 时,它只会范围到 当前请求

确保您以这种方式添加租户,即在每次请求时发生,并且在需要范围模型之前,如中间件或作为无状态认证方法(如 OAuth)的一部分。

您可以通过调用 addTenant() 来告诉 Landlord 自动范围给定的租户,无论是从 Landlord Facade 还是通过注入 TenantManager() 实例。

您可以传递租户列和 ID

Landlord::addTenant('tenant_id', 1);

或租户模型实例

$tenant = Tenant::find(1);

Landlord::addTenant($tenant);

如果传递模型实例,Landlord 将使用 Eloquent 的 getForeignKey() 方法来决定租户列名。

您可以添加所需的任意数量的租户,但是 Landlord 只允许一次只有一个类型的租户。

以下是一个示例中间件,用于实现每请求设置租户的过程。

首先创建类

php artisan make:middleware SetTenant

然后,将其编码为为认证用户设置租户 ID,您可以使用以下示例

<?php

namespace App\Http\Middleware;

use App\Models\Company;
use Closure;
use NunoMazer\Samehouse\Facades\Landlord;

class SetTenant
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (auth()->check()) {
            if (auth()->user()->company_id) {
                Landlord::addTenant('company_id', \auth()->user()->company_id);
            }
        }

        return $next($request);
    }
}

别忘了将中间件添加到 app/Http/Middleware/Kernel.http 中期望的中间件栈中

删除租户

要删除租户并停止对其范围,只需调用 removeTenant()

Landlord::removeTenant('tenant_id');

// Or you can again pass a Model instance:
$tenant = Tenant::find(1);

Landlord::removeTenant($tenant);

您还可以检查 Landlord 是否当前正在给定的租户上范围

// As you would expect by now, $tenant can be either a string column name or a Model instance
Landlord::hasTenant($tenant);

如果出于某种原因需要,您可以检索 Landlord 的租户

// $tenants is a Laravel Collection object, in the format 'tenant_id' => 1
$tenants = Landlord::getTenants();

设置您的模型

要设置一个自动范围的模型,只需使用 BelongsToTenants 特征

use Illuminate\Database\Eloquent\Model;
use NunoMazer\Samehouse\BelongsToTenants;

class ExampleModel extends Model
{
    use BelongsToTenants;
}

如果您希望覆盖特定模型的租户,可以设置 $tenantColumns 属性

use Illuminate\Database\Eloquent\Model;
use NunoMazer\Samehouse\BelongsToTenants;

class ExampleModel extends Model
{
    use BelongsToTenants;
    
    public $tenantColumns = ['tenant_id'];
}

创建新的租户范围模型

当您创建一个使用 BelongsToTenants 的模型的新实例时,如果它们尚未设置,Landlord 将自动添加任何适用的租户 ID

// 'tenant_id' will automatically be set by Landlord
$model = ExampleModel::create(['name' => 'whatever']);

查询租户范围模型

在您添加了租户后,对使用 BelongsToTenant 的模型的查询都将自动进行范围限制

// This will only include Models belonging to the current tenant(s)
ExampleModel::all();

// This will fail with a ModelNotFoundForTenantException if it belongs to the wrong tenant
ExampleModel::find(2);

注意:在开发多租户应用程序时,有时您可能会对为什么始终收到针对实际存在的行的 ModelNotFound 异常感到困惑,因为这些行属于错误的租户。

Landlord 会捕获这些异常,并将它们重新抛出为 ModelNotFoundForTenantException,以帮助您解决问题 :)

如果您需要查询所有租户,可以使用 allTenants()

// Will include results from ALL tenants, just for this query
ExampleModel::allTenants()->get()

在底层,Landlord 使用 Laravel 的 匿名全局范围。这意味着如果您同时针对多个租户进行范围限制,并且希望在一个单一查询中排除其中一个,您可以这样做

// Will not scope by 'tenant_id', but will continue to scope by any other tenants that have been set
ExampleModel::withoutGlobalScope('tenant_id')->get();

禁用租户

如果您需要禁用租户管理,请调用 disable 方法

Landlord::disable();

要再次启用它

Landlord::enable();

每次您需要检查租户是否启用时,请使用 isEnabled 方法

if (Landlord::isEnabled()) {
    // disable to execute admin tasks
    Landlord::disable();
    ...
    // enable again
    Landlord::enable();
}

贡献

如果您发现了一个问题,或者有更好的实现方法,请随时打开一个 issue 或 pull request。