# Multi-Tenancy

This module allows you to restrict access to CRUD entries only to the users who actually created them.<br>

## Video Demo

&#x20;If you want to see this module in action, here's a 5-minute video:

{% embed url="<https://www.youtube.com/watch?v=6puYh_FZE3M>" %}

## How Does It Work

\
&#x20;There are two types of Multi-Tenancy - while installing the module, you can choose:\
&#x20;\- **User Multi-Tenancy** (*every user sees only records they created*)\
&#x20;\- **Team Multi-Tenancy** (*every user sees all records created by any member of **their team***)

![](https://laraveldaily.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-19-at-11.33.46-AM.png)

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

![](https://laraveldaily.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-19-at-11.31.17-AM.png)

&#x20;First, let's talk about **User** Multi-Tenancy.

## How Does The Result Look In QuickAdminPanel Code?

\
&#x20;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');
    }
}
```

\
&#x20;Next, we have a special **Trait** for the filter by user:\
&#x20;**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');
                });
            }
        }
    }
}
```

&#x20;The code here may look complicated, but the logic is simple - whether to add global scope or not.

&#x20;Read more about Eloquent Query Scopes in [official Laravel documentaiton here](https://laravel.com/docs/master/eloquent#query-scopes).

&#x20;Finally, we use that Trait in the **model**, like **app/Customer.php**:

```
use App\Traits\MultiTenantModelTrait;

class Customer extends Model
{
    use SoftDeletes, MultiTenantModelTrait;

    // ...
```

## Team Multi-Tenancy

&#x20;For this setting, we generate separate CRUD called **Teams** where administrator can manage the teams. Also, every user may belong to multiple teams:<br>

```
class User extends Authenticatable
{
    // ...
    public function team()
    {
        return $this->belongsTo(Team::class, 'team_id');
    }
}
```

\
&#x20;And then the Trait **app/Traits/MultiTenantModelTrait.php** is expanded with logic about teams:<br>

```
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);
                });
            }
        }
    }
}
```

## How To Customize The Module?

&#x20;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');
```

{% embed url="<https://www.youtube.com/watch?v=jobtwodnH84>" %}

Another customization example, in a blog article: [Teams Multi-Tenancy: Add “Team Admin” to Manage Users](https://quickadminpanel.com/blog/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();
```
