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);
}
}
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();
}
}
@IGP from StackOverflow also answered this question and had some good insight into how things work behind the scenes. I wanted to include this here for completeness.
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).