skip to Main Content

I have three models: Group, Activity, User. With the following relationships in the models.

  • Activities belongTo a Group (with the group_id being a field in the
    activity)
  • Users belongTo a Group (with the group_id being a field in the user)
  • Likewise the Group hasMany Activities and also hasMany Users.

Users and Activities are each only associated with one group.

I want to find the users for a particular activity (via the common group). I don’t think this is a hasManyThrough relation – Eloquent complains that there isn’t a group.activity_id

How should I define the relationship between Activities and Users who share a common group_id, so that I can get the list of users for a given activity?

Group
  name:string

Activity
  name: string
  group_id: int

User
  name: string
  group_id: int
class Group extends Model
{
    public function activities(): HasMany
    {
        return $this->hasMany(Activity::class);
    }

    public function users(): HasMany
    {
        return $this->hasMany(User::class);
    }
}
class User extends Model
{
    public function group(): BelongsTo
    {
        return $this->belongsTo(Group::class);
    }
}
class Activity extends Model
{
    public function group(): BelongsTo
    {
        return $this->belongsTo(Group::class);
    }

    public function users(): HasManyThrough
    {
        return $this->hasManyThrough(User::class, Group::class);
    }
}

2

Answers


  1. Chosen as BEST ANSWER

    Thanks @IGP, that was an excellent description of what goes on behind the scenes and I'm sure it would work.
    @gych from Laracasts also answered with this, which uses the existing relations to make it really efficient:

    You have a relation for users in the Group model and a relation for group in the Activity model so you could try this to call the users relation from the group relation in the Acivity Model

      class Activity extends Model {
        public function group(): BelongsTo
        {
            return $this->belongsTo(Group::class);
        }
    
        public function users()
        {
            return $this->group->users(); 
        } 
      } 
    

  2. You can use a HasMany relationship to return a collection of models based on the query it generates with the relationship method’s parameters.

    You’re not strictly forced to user foreign keys and primary keys when using Eloquent Relationships. It’s just a (very sensible) convention.

    For Activity -> User, it’s very straightforward.

    class Activity extends Model
    {
        public function users(): HasMany
        {
            return $this->hasMany(
                related: User::class,
                foreignKey: 'group_id',
                localKey: 'group_id',
            );
        }
    }
    

    In this case the generated SQL should be something like

    SELECT * FROM {related} WHERE {related}.{foreignKey} = {$activity}.{localKey}
    

    Your HasManyThrough throws an error because it expects a different structure than what you have.

    For it to work your relationships should have been

    • if User hasMany Group
    • and Group hasMany Activity
    • then User hasManyThrough Activity (using Group as intermediate table).
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search