pronique / multitenant
MultiTenant CakePHP 插件 - 使用此插件可以轻松构建启用 SaaS 的 Web 应用程序。
Requires
Requires (Dev)
- cakephp/cakephp: 3.0.*-dev
This package is not auto-updated.
Last update: 2021-08-16 16:50:25 UTC
README
MultiTenant CakePHP 插件 - 使用此插件可以轻松构建启用 SaaS 的 Web 应用程序。
版本说明
此插件仅支持 CakePHP 3.x
项目目前正在开发中,目前处于实验阶段。
简介
最好在开始开发应用程序时实施 MultiTenant 插件,但通过一些工作,您应该能够将现有应用程序修改为使用该插件。
插件目前实现了以下多租户架构(策略):
域名策略
- 共享数据库,共享模式
- 单个应用程序实例
- 每个租户一个子域
租户
插件引入了租户的概念,租户代表每个客户账户。
租户可以有自己的用户、组和记录。数据范围到租户,租户在数据库中以账户(或您通过配置指定的任何模型/表)的形式表示。
上下文
MultiTenant 插件引入了上下文的概念,上下文是多租户插件工作的一部分。有两个预定义的上下文:“租户”和“全局”。
“全局”上下文
默认情况下,“全局”映射到 www.mydomain.com,并且您将在其中实现应用程序的非租户部分。例如,注册/注册代码。
“租户”上下文
“租户”上下文代表此租户。当用户通过子域访问应用程序时,这被认为是“租户”上下文。
自定义上下文
插件支持定义额外的上下文,这些自定义上下文映射到子域。现在,您的应用程序可以调用 MTApp::getContext()
来实现上下文感知的代码。
例如,创建一个名为“admin”的上下文并将其映射到子域“admin.mydomain.com”。
注意:上下文不是基于角色的授权的替代品,但在某些情况下可能是补充的。
作用域
您的应用程序的每个模型都可以实现五种作用域行为之一,这将根据上下文指定可访问的数据。这些作用域作为 CakePHP 行为实现。
全局作用域
全局作用域模型提供的数据可以被任何租户查询,但“租户”上下文中不允许插入/更新/删除操作。
租户作用域
在租户范围模型中提供的数据只能由所有者(租户)查询。插入操作限定于当前租户。更新和删除操作强制执行所有权,因此租户1不能更新/删除租户2的记录。
混合范围
混合范围模型在同一张表中提供全局记录和租户范围记录。当租户查询该表(在“租户”上下文中)时,将返回该租户的记录以及表中存在的全局记录。
租户插入的任何记录都限定于租户。租户不能更新/删除表中存在的全局记录。当然,租户也不能在表中选择/插入/更新/删除其他租户的记录。
共享范围
共享范围模型充当社区数据表。租户可以查询表中的所有记录,包括其他租户的记录。插入操作限定于当前租户。租户不能更新/删除其他租户的记录。
无范围
无范围模型为模型添加了范围,这是表达模型根本不设置范围的一种冗长方式。如果表有 account_id 字段,则使用插入租户的 id 来标记谁插入的记录。由于没有执行范围限制,任何租户都可以删除任何记录。
安装
composer
此插件的推荐安装方法是使用 composer。只需将其添加到您的 composer.json
配置文件中
{ "require" : { "pronique/multitenant": "master-dev" } }
git clone
或者,您可以将代码通过 git clone
直接克隆到您的应用程序中
git clone git://github.com/pronique/multitenant.git app/Plugin/MultiTenant
git submodule
或者将其添加为 git 模块,这比 git clone
更推荐,因为这样可以更容易地保持与开发同步
git submodule add git://github.com/pronique/multitenant.git app/Plugin/MultiTenant
配置
将以下内容添加到您的 config/bootstrap.php
<?php Plugin::load('MultiTenant', ['bootstrap' => true, 'routes' => false]); ?>
将以下内容添加到应用程序配置文件 app.php 的底部
/** * MultiTenant Plugin Configuration * * * ## Options * * - `strategy` - 'domain' is currently the only implemented strategy * - `primaryDomain` - The domain for the main application * value to false, when dealing with older versions of IE, Chrome Frame or certain web-browsing devices and AJAX * - `model` - The model that represents the tenant, usually 'Accounts' * - `redirectInactive` - URI to redirect when the tenant is not active or does not exist. This should be a uri at the * primary domain, usually your signup page or feature pitch page with call-to-action signup button. * - `reservedDomains` - An array of names that cannot be chosen at signup * - `contextMap` - Associative array used to define additional custom contexts besides 'global' and 'tenant', * i.e. when domain admin.domain.com is matched MTApp::getContext() will return the custom context 'admin'. * - `ScopedBehavior` - Application wide defaults for the ScopedBehavior Behavior * - `MixedBehavior` - Application wide defaults for the MixedBehavior Behavior * */ 'MultiTenant' => [ 'strategy'=>'domain', 'primaryDomain'=>'www.example.com', 'model'=>[ 'className'=>'Accounts', 'field'=>'domain', //field of model that holds subdomain/domain tenants 'conditions'=>['is_active'=>1] //query conditions to match active accounts ], 'redirectInactive'=>'/register', 'reservedDomains'=>[ 'admin', 'superuser', 'system', 'www' ], 'contextMap' => [ 'admin'=>'admin.example.com' //an example of a custom context ], 'scopeBehavior'=>[ 'global_value'=>0, //global records are matched by this value 'foreign_key_field'=>'account_id' //the foreign key field that associates records to tenant model ] ]
注意:粘贴上述配置时,别忘了在底部配置部分添加逗号。config\app.php 中的语法错误会导致静默失败(空白页面)。
使用方法
MTApp
MTApp
是一个静态类,您可以在应用程序的任何地方调用它。
use MultiTenant\Core\MTApp; //Returns an entity of the current tenant $tenant = MTApp::tenant(); echo $tenant->id; //output 1 //Or the same thing in a single line; echo MTApp::tenant()->id; //output 1 //Another Example, you can reference any field in the underlying model echo MTApp::tenant()->name; //output Acme Corp.
use MultiTenant\Core\MTApp; // Based on URL, we are in a tenant's sudomain, customera.example.com echo MTApp::getContext(); //output 'tenant' // Based on URL, we are in at the primary sudomain www.example.com echo MTApp::getContext(); //output 'global' // Assumming we have defined a custom context, we are in at the sudomain admin.example.com echo MTApp::getContext(); //output 'admin' var_dump( MTApp::isPrimary() ); //returns true if we are at the primaryDomain, false if we are at a tenant's subdomain or in a custom context.
您可以通过使用完整命名空间来调用类而省略 use MultiTenant\Core\MTApp;
行
\MultiTenant\Core\MTApp::tenant();
行为使用示例
TenantScopeBehavior
class SomeTenantTable extends Table { public function initialize(array $config) { ... $this->addBehavior('MultiTenant.TenantScope'); ... } ... }
MixedScopeBehavior
class SomeMixedTable extends Table { public function initialize(array $config) { ... $this->addBehavior('MultiTenant.MixedScope'); ... } ... }
GlobalScopeBehavior
class SomeCommonTable extends Table { public function initialize(array $config) { ... $this->addBehavior('MultiTenant.GlobalScope'); ... } ... }
SharedScopeBehavior
class SomeSharedTable extends Table { public function initialize(array $config) { ... $this->addBehavior('MultiTenant.SharedScope'); ... } ... }
无范围行为
class JustARegularTable extends Table { public function initialize(array $config) { ... $this->addBehavior('MultiTenant.NoScope'); ... } ... }
错误
如果您偶然发现了一个错误,请随时创建一个带有修复方案、错误描述以及错误解决方法的pull request。
功能
提出新的功能建议的最佳方式是通过pull request。