使用相同的Laravel安装来运行多个网站,同时将租户特定的数据分开以实现完全独立的多域设置。没错你没听错,就是这么爽,Saas项目的福音,由此可见laravel有多香。目前这个包还在维护中,使用人数就已经超过1000了,我花了3-5天研究了一下这个东西,是真的香。由于是歪果仁开发的,所以文档对国内开发者不是特别友好,造成了众多小伙伴使用不便,这里我就给大家分享一下我的经验。
很多人不理解这个包是干什么的,所以上去就开始看文档,这样很浪费时间。正如文章开头说的,使用相同的Laravel安装来运行多个网站,同时将租户特定的数据分开以实现完全独立的多域设置。其原理就是配置生成的子域会同时生成相对应的数据库,生成的域和数据库由包的内置程序生成的UUID来绑定关系,访问域名的时候程序就会访问对应的数据库,从而实现多租户之间的数据隔离(传统意义上的分库)。你要说它的用处在哪,那就是多用于Saas服务,同一套代码不需要重新部署服务器环境就可以提供给多个用户(这里大多都是需要建站的客户)使用,而租户之间的数据是隔离的,也可用于b2b开发等。现在你大概知道它是干什么的吧。
这里我以laravel生态中的一个开源电商cms来讲解具体如何使用它。
1.首先你得确保本地安装好一个项目并可以运行,这里我就不演示了,我本地的项目就是Bagisto(cms项目),地址是https://xueyuanjun.com/post/19446.html
2.安装hyn包,composer安装不用多说了吧,都懂。
安装之前的环境配置:
由于这里的cms项目是laravel5.6的,所以我使用的是hyn5.3,这里顺带一提hyn目前更新到5.5版本,但不是特别稳定,官方推荐使用5.4版。顺带一提,国内常用的PHP本地开发集成环境一般使用的是wamp和PHPstudy等,这里我建议使用后者,PHPstudy目前已更新到8.1版,功能强大方便实用,php开发者必备神器!
安装准备:
a.本地数据库准备(这里我使用的是mysql),由于多租户的数据是分库来处理的,所以需要数据库用户有创库权限,利用的是mysql的“GRANT OPTION”特性,在本地mysql中运行以下代码:
CREATE DATABASE IF NOT EXISTS bagisto;
CREATE USER IF NOT EXISTS root@localhost IDENTIFIED BY 'yourPASSWORD';
GRANT ALL PRIVILEGES ON *.* TO root@localhost WITH GRANT OPTION;
*注意这里的“bagisto”是我本地cms的数据库,下面会说明会将其设置为系统数据库,给root用户权限。
b.配置系统数据库,在你的项目中config/database.php中创建系统数据库连接配置:
'system' => [
'driver' => 'mysql',
'host' => env('TENANCY_HOST', '127.0.0.1'),
'port' => env('TENANCY_PORT', '3306'),
'database' => env('TENANCY_DATABASE', 'bagisto'),
'username' => env('TENANCY_USERNAME', 'root'),
'password' => env('TENANCY_PASSWORD', 'yourPASSWORD'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
]
*注意建议将配置信息写到.env文件中,不需要创建'tenant'数据库配置项,hyn包在连接租户数据库情况下会自动创建'tenant'连接
c.在config/tenancy.php配置里将website->uuid-limit-length-to-32状态设置为开启
安装:
运行composer命令以添加租赁包作为依赖项
composer require "hyn/multi-tenant:5.3.*"
发布配置文件和迁移以进行租用,配置软件包
php artisan vendor:publish --tag=tenancy
选择你要迁移的数据库迁移,主要是生成hostname和websites表
php artisan migrate --database=system
生成了system连接库的迁移文件后,就可将其库内表迁移到新建的网站库里了,在tenancy.php
配置中,将其设置db > tenant-migrations-path
为有效的绝对路径,并且默认情况下,所有新租户将运行这些迁移。
// ..
"tenant-migrations-path" => database_path('migrations/tenant'),
// ..
如果你还想填充新创建和迁移的租户的数据库,则可以db > tenant-seed-class
在tenancy.php
配置文件中启用。将此设置更改为完全命名空间的类名,程序包将在运行自动迁移后自动运行该迁移。
租赁已将--website_id[=WEBSITE_ID]
选项添加到以下每个本机Laravel迁移和种子命令中,并相应地为其命名空间。
tenancy:migrate
-运行数据库迁移tenancy:migrate:refresh
-重置并重新运行所有迁移tenancy:migrate:reset
-回滚所有数据库迁移tenancy:migrate:rollback
-回滚上一次数据库迁移tenancy:db:seed
-用记录为数据库播种--website_id可选选项接受多个值。尽管是可选的,但如果保留该选项,它将对所有租户运行该命令。例如:
php artisan tenancy:migrate --website_id=1
仅迁移租户网站1。php artisan tenancy:migrate --website_id=1 --website_id=2
迁移租户网站1和2。php artisan tenancy:migrate
迁移所有租户网站。 该website_id
对应了自动递增id
的网站列并不是UUID。
至此你的安装算是完成了。
3.创建网站和使用
文档中给出的代码示例很清晰,但如果你是像我一样为cms部署多网站访问,你就会进入误区,这段创建新站的代码在那里写?!如果你正在开发一个新项目,那这段建站代码就是你要开发的建站功能,在哪里写就不用多说了吧!但如果你和我一样,是为了节约开发成本,部署一个cms的多站访问,那就可以直接php artisan tinker运行建站代码。这里我就以我的方式来讲解。
在调试台中运行建站代码之前,你需要知道hyn访问子域的原理。我们都知道,如果你在本地部署一个项目就必须通hostname来访问(这里以apache服务举例),这个时候在apache中就会生成一个vhost文件,这个conf文件的作用就不用多说了吧,而建站代码中会生成一个conf文件在项目中(位置在storage/app/tenancy/webserver/apache2/),这个时候你需要在本地服务的配置文件中将这个生成的临时conf加载到本地apache服务中,而hyn就会依据这个临时conf文件去访问这个项目(注意此时的临时conf文件和创建的子域是有绑定关系的,这个在建站代码中逻辑清晰可见)。所以你需要做的有两步:
a.在项目config/webserver.php中开启生成临时conf文件配置apache2->enabled,注意这里是一非常重要的步骤,生成的临时文件不会自动加载到apache服务中,如果你是在本地部署,那只需要重启本地apache服务,如果是在生产环境中,就必须修改websrever.php文件中重新启动apache服务的命令,否则你每创建一个新站就要重启线上环境,修改代码如下:
/**
* Actions to run to work with the Apache2 service.
*/
'actions' => [
/**
* Action that asserts Apache2 is installed.
*/
'exists' => 'F:/phpstudy_pro/Extensions/Apache2.4.39/bin',
/**
* Action to run to test the apache configuration.
*
* @set to a boolean to force the response of the test command.
* @info true succeeds, false fails
*/
'test-config' => 'httpd -t',
/**
* Action to run to reload the apache service.
*
* @info set to null to disable reloading.
*/
'reload' => 'httpd -k restart'
]
如何修改就不多说,根据你线上apache命令将httpd命令替换即可。
b.在apache的配置文件中加载临时vhost文件的路径,只需添加以下代码(我本地)
IncludeOptional F:/phpstudy_pro/WWW/bagisto/storage/app/tenancy/webserver/apache2/*.conf
线上环境自行修改加载路径。
创建并绑定网站(这里我是php artisan tinker直接运行):
use Hyn\Tenancy\Models\Website;
use Hyn\Tenancy\Contracts\Repositories\WebsiteRepository;
use Hyn\Tenancy\Models\Hostname;
use Hyn\Tenancy\Contracts\Repositories\HostnameRepository;
$website = new Website;
app(WebsiteRepository::class)->create($website);
$hostname = new Hostname;
$hostname->fqdn = 'dev.example.com';
$hostname = app(HostnameRepository::class)->create($hostname);
app(HostnameRepository::class)->attach($hostname, $website);
这里生成的UUID是绑定网站和数据库关系的标识,长度为32位,如果不想使用系统中创建UUID的方法,文档中也提供了另一种方法。
新站的访问:
前文已经提到,创建新站(也可是子域)后就会生成这个网站对应的数据库,但当前这个数据库是一个空库,要实现原项目的所有功能就必须将system连接的库中所有表迁移过来,所以下一步就是将system连接库的表迁移到当前库里(迁移表不填充数据,为了在访问时区分是否是新站)。一般的项目都不会将数据库的表直接创建成迁移文件放在项目中,所以这个时候就需要逆向将表创建成迁移文件,再执行迁移命令将表迁移到新库中,这里顺带给大家安利一下另一个laravel的工具(xethron/migrations-generator)。安装依赖和执行命令如下:
composer require --dev "xethron/migrations-generator"
下载完成后再app中注册服务
// 省略之前内容
'providers' => [
// 省略之前内容
Way\Generators\GeneratorsServiceProvider::class,
Xethron\MigrationsGenerator\MigrationsGeneratorServiceProvider::class,
],
指定某张表生成迁移文件
php artisan migrate:generate table1,table2,table3
反向忽略某些表
php artisan migrate:generate --ignore="table3,table4,table5"
*注意这里的system连接数据库中,hostname和websites表不需要迁移,所以建议忽略这两张表
4.访问新建站点
a.访问你新建的站点“dev.example.com”,如果你本地使用的是PHPstudy8.1,可能会出现无法解析php文件的问题,这是因为生成的临时vhost文件中没有加载使用php的路径,而新版PHPstudy8.1中vhost文件配置了php的加载路径,这是为了可以选用php版本而添加的配置项,所以你需要修改临时的vhost文件(可建立“www.example.com”vhost文件,仿照修改)。如果你觉得这样麻烦还可以去修改生成临时vhost文件的模板,在vendor/hyn/multi-tenant/assets/generators/webserver/apache/blocks/中。
b.访问成功后测试数据是否是新库数据(或者连接的是否是新库)。
hyn在访问新站点域名时会自动生成一个tenant连接,这个连接对应的数据库即是当前网站的数据库,不过在这之前,你需要在所有映射表model里面use 两个Traits,即Notifiable和UsesTenantConnection,否则访问的任然是system连接库,或者可以使用租户路由(这里不多做解释,可以查看文档)。
至此,hyn就算是运用成功了。
整理不易,转载请带出处!!!
参考文档https://tenancy.dev/docs