I’m building a role based multi-tenancy system in my Laravel 12 project. a User
is given a Role
within a Company
, they can only have one role within a company, but can have multiple companies assigned to them. My ideal end set up is to be able to query the user, with the company, and optionally the role and have some output that looks like this:
{
"email": "[email protected]",
"company": {
"id": 1,
"name": "Acme",
"pivot": {
"role_id"; 1,
"role": {
"role": "admin"
}
}
}
}
or…
{
"email": "[email protected]",
"company": {
"id": 1,
"name": "Acme",
"role": {
"role": "admin"
}
}
}
I have a CompanyEntry
model which currently creates unique combinations by the company, user and role, it looks like:
Schema::create('company_entries', function (Blueprint $table) {
$table->id();
// must link to a user that logs in.
$table->foreignId('user_id')->index()->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->foreignId('company_id')->index()->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->foreignId('role_id')->index()->constrained()->cascadeOnUpdate()->cascadeOnDelete();
// booleans
$table->boolean('is_default')->default(0)->index();
// date/times
$table->timestamps();
// compound index
$table->index(['user_id', 'company_id']);
$table->index(['user_id', 'company_id', 'role_id']);
// create unique index
$table->unique([
'user_id',
'company_id',
'role_id'
], 'unique_user_company_index');
});
How would I achieve the desired end result given the existing relationship on my User
model:
/**
* Get the default company associated with the user
*/
public function company(): HasOneThrough
{
return $this->hasOneThrough(
Company::class,
CompanyEntry::class,
'user_id',
'id',
'id',
'company_id'
)->where('is_default', true)->orderBy('created_at', 'asc');
}