danthedj/multitenant2

Laravel 租户动态数据库解决方案。

v1.9.0 2021-10-10 23:30 UTC

This package is auto-updated.

Last update: 2024-09-11 06:05:48 UTC


README

Build Status

The Laravel 5.4 MultiTenant package enables you to easily add multi-tenant capabilities to your application. This package is designed using a minimalist approach.Just drop it in, run the migration, and start adding tenants. Your applications will have access to current tenant information through the dynamically set config('tenant') values. Optionally, you can let applications reconnect to the default master database so a tenant could manage all tenant other accounts for example. And, perhaps the best part, Artisan is completely multi-tenant aware! Just add the --tenant option to any command to run that command on one or all tenants. Works on migrations, queueing, etc.!

MultiTenant also offers a TenantContract, triggers Laravel events, throws a TenantNotResolvedException and TenantDatabaseNameEmptyException, so you can easily add in custom functionality and tweak it for your needs.

Laravel MultiTenant was forked from @thinksaydo, who modified the original Tenantable project by @leemason. All of the main code is due to them. The difference in this project is that it allows for a database per tenant, compared to a single database with table prefixes. This allows for a more managed approach in some cases.

MultiTenant relies on your ENV and Database config and stores just the connection name in the table and only allows one subdomain and domain per tenant, which is most often plenty for most apps. MultiTenant also throws a TenantNotResolvedException when tenants are not found, and a TenantDatabaseNameEmptyException when the database name could not be determined.

简单安装与使用

Composer 安装

composer require danthedj/multitenant

生成 composer 自动加载文件

composer dump-autoload

租户数据库表安装(使用默认数据库连接)

artisan migrate --path /vendor/danthedj/multitenant/migrations

服务提供者安装

解析每个路由/请求

如果你想在每个路由/请求上解析客户端,请将其添加到

DanTheDJ\MultiTenant\TenantServiceProvider::class,

config/app.php 中的服务提供者数组中

注意: 这将是 Laravel 5.5(及以上版本)默认使用的自动发现方式。如果你想使用中间件选项,请将以下内容添加到你的项目 composer.json 文件中。

    "extra": {
        "laravel": {
            "dont-discover": [
                "DanTheDJ\\MultiTenant\\TenantServiceProvider"
            ]
        }
    }

通过中间件解析租户

如果你只想在路由上使用中间件来解析租户,请将其添加到

DanTheDJ\MultiTenant\Providers\TenantMiddlewareServiceProvider::class,

config/app.php 中的服务提供者数组中 而不是 上述服务提供者。

数据库连接

config/database.php 中创建一个新的连接。对于 hostportusernamepassword,这些将从 .env 文件中获取。

'tenant_db' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => '', // The database name will be filled in dynamically upon the tenant being resolved.
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'database_prefix' => '', // this can be changed and represents a database prefix e.g. 'business_acme'.
    'strict' => true,
    'engine' => null,
],

租户创建(仅使用标准 Eloquent 模型)

$tenant = new \DanTheDJ\MultiTenant\Tenant();
$tenant->name = 'ACME Inc.';
$tenant->email = 'person@acmeinc.com';
$tenant->subdomain = 'acme';
$tenant->alias_domain = 'acmeinc.com';
$tenant->connection = 'tenant_db';
$tenant->meta = ['phone' => '123-123-1234'];
$tenant->save();

完成!简约,简单。每当你的应用通过 http://acme.domain.comhttp://acmeinc.com 访问时,连接 "tenant_db" 将被使用,数据库名称将切换到 "{prefix}_acme",并设置 config('tenant') 为租户详细信息,允许你从视图或应用中访问值。

高级 EnvTenant 使用

Artisan

// migrate master database tables (in tenant database)
php artisan migrate

// migrate specific tenant database tables
php artisan migrate --tenant=acme

// migrate all tenant database tables
php artisan migrate --tenant=*

--tenant 选项适用于所有 Artisan 命令

php artisan migrate:rollback --tenant=acme

你也可以在调试时使用 --tenant 选项

php artisan tinker --tenant=acme

租户

\DanTheDJ\MultiTenant\Tenant 类是一个简单的 Eloquent 模型,提供基本的租户设置。

$tenant = new \DanTheDJ\MultiTenant\Tenant();

// The unique name field identifies the tenant profile
$tenant->name = 'ACME Inc.';

// The non-unique email field lets you email tenants
$tenant->email = 'person@acmeinc.com';

// The unique subdomain field represents the subdomain portion of a domain and the database table prefix
// Set subdomain and alias_domain field to NULL to access tenant by ID instead
$tenant->subdomain = 'acme';

// The unique alias_domain field represents an alternate full domain that can be used to access the tenant
// Set subdomain and alias_domain field to NULL to access tenant by ID instead
$tenant->alias_domain = 'acmeinc.com';

// The non-unique connection field stores the Laravel database connection name
$tenant->connection = 'db1';

// The meta field is cast to an array and allows you to store any extra values you might need to know
$tenant->meta = ['phone' => '123-123-1234'];

$tenant->save();

租户解析器

\DanTheDJ\MultiTenant\TenantResolver 类负责在 Web 和 Artisan 访问期间解析和管理活动租户。您可以使用 app('tenant') 访问解析器类。

// get the resolver instance
$resolver = app('tenant');

// check if valid tenant
$resolver->isResolved();

// get the active tenant (returns Tenant model or null)
$tenant = $resolver->getActiveTenant();

// get all tenants (returns collection of Tenant models or null)
$tenants = $resolver->getAllTenants();

// activate and run all tenants through a callback function
$resolver->mapAllTenants(function ($tenant) {});

// reconnect default connection enabling access to "tenants" table
$resolver->reconnectDefaultConnection();

// reconnect tenant connection disabling access to "tenants" table
$resolver->reconnectTenantConnection();

如果您想使用自定义模型,请注册一个自定义服务提供者,将单例绑定到 TenantContract 并解析为您的自定义租户模型实例。只要在加载 EnvTenant\TenantServiceProvider 之前加载您的服务提供者,EnvTenant 就会自动回退到您的自定义模型。

在您的 app/Providers 文件夹中创建此示例服务提供者,命名为 CustomTenantServiceProvider.php。

<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Tenant;

class CustomTenantServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->app->singleton('TenantContract', function()
        {
            return new Tenant();
        });
    }

    public function register()
    {
        //
    }
}

然后在您的 config/app.php 文件中注册 App\Providers\CustomTenantServiceProvider::class

事件

在整个生命周期中会触发事件,允许您监听和自定义行为。

租户激活

DanTheDJ\MultiTenant\Events\TenantActivatedEvent

租户解析

DanTheDJ\MultiTenant\Events\TenantResolvedEvent

租户未解析

DanTheDJ\MultiTenant\Events\TenantNotResolvedEvent

通过 Web 未解析租户,将抛出异常

DanTheDJ\MultiTenant\Events\TenantNotResolvedException

无法确定或租户数据库名称为空

DanTheDJ\MultiTenant\Events\TenantDatabaseNameEmptyException