Người viết: Phan Thanh
Multi-Tenancy is a single instance of software that serves multiple customers privately.
Hiểu đơn giản Multi-Tenancy là một hệ thống web application có nhiều khách hàng cùng sử dụng nhưng dữ liệu giữa các khách hàng hoàn tập độc lập, khách hàng này không thể truy cập vào dữ liệu của khách hàng kia.
Có thể kể đến vài ví dụ như:
Bài toán multi-tenancy thực tế gặp rất nhiều và tùy theo từng hệ thống sẽ triển khai theo mỗi cách khác nhau. Ở bài viết này, mình sẽ cùng bạn tìm hiểu để implement một cách đơn giản nhất vào project Laravel Framework nhé (Vì mình cũng đang tìm hiểu chưa có biết nhiều)
Có một hệ thống quản lí khách sạn và danh sách book phòng theo từng khách sạn.
Vấn đề:
Tạo thêm 1 trường created_by_user_id
trong bảng hotels
. Trường này dùng để xác định ông nào đã tạo ra cái khách sạn ấy trên hệ thống.
1
2
3
4
5
6
|
Schema::table('hotels', function (Blueprint $table) {
$table->unsignedBigInteger('created_by_user_id');
$table->foreign('created_by_user_id')->references('id')->on('users');
});
|
Sau đó, thêm created_by_user_id
vào fillable trong Model
1
2
3
4
5
6
7
8
9
10
|
protected $fillable = [
'title',
'name',
'address',
'created_at',
'updated_at',
'created_by_user_id',
];
|
Bây giờ làm sao để field tự insert vào DB khi user tạo mới một Hotels? Bạn có thể sử dụng Model Observers. Tuy nhiên để mở rộng và tái sử dụng ở các Model khác nhau, mình sẽ tạo ra 1 Trait Multitenantable
thay vì cứ mỗi Model mình lại tạo ra 1 Observers như vầy.
Tạo file app/Traits/Multitenantable.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
namespace App\Traits;
trait Multitenantable {
protected static function bootMultitenantable()
{
if (auth()->check()) {
static::creating(function ($model) {
$model->created_by_user_id = auth()->id();
});
}
}
}
|
bootMultitenantable()
với name convention là bootXYZ()
, Laravel sẽ tự chạy hàm này khi Trait được sử dụng (Có thể gọi nó là trait “constructor”)Trait Multitenantable sẽ có nhiệm vụ khi user đó tạo một thứ gì đó thì nó tự động insert vào DB ở field created_by_user_id
với value là id của user đang đang nhập.
Implement trait này vào model Hotel
1
2
3
4
5
6
7
8
9
10
11
|
use App\Traits\Multitenantable;
// ...
class Hotel extends Model
{
use Multitenantable;
// ...
}
|
Kết quả khi tạo mới 1 Hotel:
Có thể bạn quan tâm
Học lập trình thế nào để không thất nghiệp?
Đây là bước quan trọng nhất để giải quyết bài toán: Tất cả dữ liệu khách sạn của ông A và ông B hoàn toàn độc lập, không liên quan và không ai có thể thấy hay truy cập vào các dữ liệu của người khác.
Trong Laravel rất đơn giản, ta dùng Global Scope để fillter tất cả các query trên Model.
Thêm vào trait Multitenantable
như sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
namespace App\Traits;
use Illuminate\Database\Eloquent\Builder;
trait Multitenantable {
protected static function bootMultitenantable()
{
if (auth()->check()) {
static::creating(function ($model) {
$model->created_by_user_id = auth()->id();
});
static::addGlobalScope('created_by_user_id', function (Builder $builder) {
$builder->where('created_by_user_id', auth()->id());
});
}
}
}
|
Oki, lúc này nó sẽ lọc tất cả các khách sạn của user đang nhập hiện tại, còn các khách sạn của user khác hoàn toàn ko hiển thị và không access vào được.
SQL thuần nó sẽ như này:SELECT * FROM hotels WHERE created_by_user_id=1
(với 1 là id của user đang đăng nhập).
Kết quả ở Hotel list:
Thử truy cập vào thằng hotel có id=1 mà chưa set trường created_by_user_id
:
404 ngay
Bây giờ bạn thử set created_by_user_id=2
, back lại và xem kết quả nhé (Thêm 1 record ở list + có thể access vào rồi)
Ngoài ra để đảm bảo thằng Admin có thể view được hết các dữ liệu trên hệ thống thì bạn check thêm if nhé.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
protected static function bootMultitenantable()
{
if (auth()->check()) {
static::creating(function ($model) {
$model->created_by_user_id = auth()->id();
});
// if user is not administrator - role_id 1
if (auth()->user()->role_id != 1) {
static::addGlobalScope('created_by_user_id', function (Builder $builder) {
$builder->where('created_by_user_id', auth()->id());
});
}
}
}
|
Ok, vậy là coi như mình đã implement Multi-Tenancy trên model Hotels rồi.
Giờ muốn tái sử dụng Trait này
, thì bạn cứ use trong Model
là ngon ngay (Nhớ model implement phải có trường created_by_user_id)
Trên đây mình đã giới thiệu với bạn Multi-Tenancy là gì? Cách implement Multi-Tenancy một cách đơn giản nhất vào project Laravel Framework như thế nào. Hi vọng từ bài viết này bạn có thể hiểu về Multi-Tenancy và áp dụng vào các bài toán của mình.
Nguồn: Sưu tầm từ internet via Viblo