@oscaribarra25 HasManyThrough might will work here. https://laravel.com/docs/11.x/eloquent-relationships#has-many-through
Relation from a model to another with a model between
Hi,
I have a question just to know if I am doing things rights or if there is a more "elegant" way to do this.
I have these three models Ability, Role, User which DB schemas are created as follows (only relevants fields are shown):
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
//Other fields here
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
};
return new class extends Migration
{
public function up()
{
Schema::create('abilities', function (Blueprint $table) {
$table->id();
//Other fields here
});
}
public function down()
{
Schema::dropIfExists('abilities');
}
};
return new class extends Migration
{
public function up()
{
Schema::create('roles', function (Blueprint $table) {
$table->id();
//Other fields here
});
}
public function down()
{
Schema::dropIfExists('roles');
}
};
return new class extends Migration
{
public function up()
{
Schema::create('ability_role', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('ability_id');
$table->foreign('ability_id')
->references('id')->on('abilities')
->onDelete('cascade')
->onUpdate('cascade');
$table->unsignedBigInteger('role_id');
$table->foreign('role_id')
->references('id')->on('roles')
->onDelete('cascade')
->onUpdate('cascade');
//Other fields here
$table->unique([ 'ability_id', 'role_id' ]);
});
}
public function down()
{
Schema::dropIfExists('ability_role');
}
};
return new class extends Migration
{
public function up()
{
Schema::create('role_user', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('role_id');
$table->foreign('role_id')
->references('id')->on('roles')
->onDelete('cascade')
->onUpdate('cascade');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade')
->onUpdate('cascade');
//Other fields here
$table->unique([ 'role_id', 'user_id' ]);
});
}
public function down()
{
Schema::dropIfExists('role_user');
}
};
And the models are as follows (only relevant methods are shown):
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
/**
*
*/
class User extends Authenticatable
{
//Other uses and properties here
public function roles()
{
return $this->belongsToMany(Role::class);
}
//Other methods here
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
//Other class constants here
public function abilities()
{
return $this->belongsToMany(Ability::class)->withTimestamps();
}
public function users()
{
return $this->belongsToMany(User::class);
}
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Ability extends Model
{
//Other class constants here
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
I am trying to add a new method to User model to get all the abilities it has according to the roles it is related to. I end up doing this using Eloquent and a repository method as follows:
namespace App\Repositories;
use App\Models\Ability;
use App\Repositories\Interfaces\SecurityRepositoryInterface;
class SecurityRepository implements SecurityRepositoryInterface
{
//Other repository methods here
public static function getUserAbilities($user_id)
{
return Ability::whereHas('roles', function($query1) use ($user_id) {
$query1->whereHas('users', function($query2) use ($user_id) {
$query2->where('users.id', $user_id);
});
})->get();
}
}
And then in the user model
public function abilities()
{
return SecurityRepository::getUserAbilities($this->id);
}
But I am wondering is there is a way to do this using anything relation-wise like $this->hasMany, $this->belongsToMany, etc.
Can anyone get me some lights on this?
Best regards,
Please or to participate in this conversation.