Multi-Tenancy
This module allows you to restrict access to CRUD entries only to the users who actually created them.
If you want to see this module in action, here's a 5-minute video:
There are two types of Multi-Tenancy - while installing the module, you can choose:
- User Multi-Tenancy (every user sees only records they created)
- Team Multi-Tenancy (every user sees all records created by any member of their team)

After installing the module, you will see a checkbox for each CRUD separately, whether to use this restriction setting.

First, let's talk about User Multi-Tenancy.
First, for every affected CRUD we add a field created_by_id with relationship to User model:
class Customer extends Model
{
// ...
public function created_by()
{
return $this->belongsTo(User::class, 'created_by_id');
}
}
Next, we have a special Trait for the filter by user:
app/Traits/MultiTenantModelTrait.php
trait MultiTenantModelTrait
{
public static function bootMultiTenantModelTrait()
{
if (!app()->runningInConsole() && auth()->check()) {
$isAdmin = auth()->user()->roles->contains(1);
static::creating(function ($model) use ($isAdmin) {
// Prevent admin from setting his own id - admin entries are global.
// If required, remove the surrounding IF condition and admins will act as users
if (!$isAdmin) {
$model->created_by_id = auth()->id();
}
});
if (!$isAdmin) {
static::addGlobalScope('created_by_id', function (Builder $builder) {
$builder->where('created_by_id', auth()->id())->orWhereNull('created_by_id');
});
}
}
}
}
The code here may look complicated, but the logic is simple - whether to add global scope or not.
Finally, we use that Trait in the model, like app/Customer.php:
use App\Traits\MultiTenantModelTrait;
class Customer extends Model
{
use SoftDeletes, MultiTenantModelTrait;
// ...
For this setting, we generate separate CRUD called Teams where administrator can manage the teams. Also, every user may belong to multiple teams:
class User extends Authenticatable
{
// ...
public function team()
{
return $this->belongsTo(Team::class, 'team_id');
}
}
And then the Trait app/Traits/MultiTenantModelTrait.php is expanded with logic about teams:
trait MultiTenantModelTrait
{
public static function bootMultiTenantModelTrait()
{
if (!app()->runningInConsole() && auth()->check()) {
$isAdmin = auth()->user()->roles->contains(1);
static::creating(function ($model) use ($isAdmin) {
if (!$isAdmin) {
$model->team_id = auth()->user()->team_id;
}
});
if (!$isAdmin) {
static::addGlobalScope('team_id', function (Builder $builder) {
$field = sprintf('%s.%s', $builder->getQuery()->from, 'team_id');
$builder->where($field, auth()->user()->team_id)->orWhereNull($field);
});
}
}
}
}
All the logic of that module is inside of app/Traits/MultiTenantModelTrait.php file. So whatever you want to customize, you should do it there.
For example, you may want to customize how administrator records are treated. By default, entries created by administrator role user are visible to everyone, because they are considered "system records". If you want to change that, you need to delete orWhereNull('created_by_id') condition in the Trait:
$builder->where('created_by_id', auth()->id())->orWhereNull('created_by_id');
Another customization example, in a blog article: Teams Multi-Tenancy: Add “Team Admin” to Manage Users
For more complex logic, you can copy-paste some logic and create another trait, and use your trait in some models you want.
Finally, if on some models or some queries you want to disable that filtering, there is a method called withoutGlobalScope():
User::withoutGlobalScopes()->get();
Last modified 2yr ago