Now, let's filter the records by my current team. For that, we will add tenant_id
column to all the DB tables that should be "tenantable". We create a Trait, and this will be a lesson about Traits and Scopes, similar like we had in one earlier lesson.
So, let's generate two migrations to add tenant_id
to projects
and tasks
tables.
php artisan make:migration "add tenant id to projects table"php artisan make:migration "add tenant id to tasks table"
database/migrations/xxx_add_tenant_id_to_projects_table.php:
Schema::table('projects', function (Blueprint $table) { $table->foreignId('tenant_id')->constrained();});
database/migrations/xxx_add_tenant_id_to_tasks_table.php:
Schema::table('tasks', function (Blueprint $table) { $table->foreignId('tenant_id')->constrained();});
Now, let's create a trait, FilterByTenant
.
php artisan make:trait Traits/FilterByTenant
We will use the same booted()
method for the creating
event and a global scope in the trait.
app/Traits/FilterByTenant.php:
use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Builder; trait FilterByTenant{ protected static function booted(): void { $currentTenantId = auth()->user()->tenants()->first()->id; static::creating(function (Model $model) use ($currentTenantId) { $model->tenant_id = $currentTenantId; }); static::addGlobalScope(function (Builder $builder) use ($currentTenantId) { $builder->where('tenant_id', $currentTenantId); }); }}
We haven't added the tenant's relationship to the User
Model.
app/Models/User.php:
use Illuminate\Database\Eloquent\Relations\BelongsToMany; class User extends Authenticatable{ // ... public function tenants(): BelongsToMany { return $this->belongsToMany(Tenant::class); }}
We must add this trait to the Project
and Task
Models.
app/Models/Project.php:
use App\Traits\FilterByTenant; class Project extends Model{ use FilterByTenant; // ...}
app/Models/Task.php:
use App\Traits\FilterByTenant; class Task extends Model{ use FilterByTenant; // ...}
Cool, so we're filtering the records by active tenant. Next, what if the user has multiple tenants? How to switch between them?
I'm trying to test this using phpunit. But
auth()->user()
is null in the test even with$this->actingAs()
or$this->be()
Please let me know how to access the user instance.Should be working, can't really help without debugging your code on why the user doesn't stay active.
Thanks for zooming in when typing small fonts. For instance, when making a trait class.
Isn't $currentTenantId the first tenant of the user as a single user can belong to multiple tenants?
It is! But that was the point of this lesson. At the start of the next lesson, we move this variable to a different place to allow switching tenant ID :)
Ohhh...
I think I imagined it too earlier. :)
Thanks
I test my relationships on tinker. Adding this global scope, I'm unable to test them as it gives error due to user_id constraint on the models.
Is there a way to test relationships on tinker with this global scope applied or do I have to disable my trait each time I'm testing?