简体   繁体   中英

Laravel/Eloquent - Modeling a HasOne relationship via a BelongsToMany relationship

Say I have four tables:

  • users
  • groups
  • activities
  • group_activities

Where a group can have any number of activities and an activity can belong to any number of groups through their intermediate table group_activities , and a user belongs to one group via users.group_id . I want to correctly model a relationship between users and activities so that a user can have any one activity, but only if the group that user belongs to has a relation to that activity.

HasOneThrough doesn't seem to work here, since the group the user is related through has multiple activities. HasManyThrough doesn't work since the user can only have one.

I want to properly model this relationship so that it can be picked up for selection automatically via a Nova relationship field, but I'm struggling to figure out exactly how I would do so. My first thought is a HasOneThrough relation with some set of subqueries, but I can't quite piece together where to start.

How would I do this, or conversely, is it possible via Eloquent's automatic relationship system at all?

To ensure we are on the same idea of your relationships:

The relationship between Groups and Activities is a Many To Many relationship ( Many To Many - Larvel Documentation ).

The group_activities table is the pivot table.

The relationship between users and groups is a One To Many relationshipOne To Many - Larvel Documentation and the inverse of it One To Many (Inverse) - Larvel Documentation .

To actually answer your question:

If you want to use a shortcut from users to their activities, the Has Many Through is the correct way. If a group can have arbitrary many activities, and a user belongs to one group, the user will be associated to these arbitrary many activities through the group -hence Has Many Through. Note that this is not really a separate relationship though, it's just a convient shortcut.

If you wan't to associate a user with a single Activity directly, you need to to this via a separate One to Many relationship between Users and Activities.

I'm not entirely sure if I interpret your question correctly, so the following is just an assumption, but do you want to ensure a user can only be associated to an activity thats also associated with the user group? So to restrict possible activites by group? If that is the case, you'd simply need to check if the selected activity is in the activities associated with the users group:

With your relationships set up like this:

class User {

    public function activity(){
        return $this->belongsTo('App\Activity');
    }

    public function possibleActivities(){
         return $this->hasManyThrough('App\Activity','App\Group');
    }
}

you can check and associate activities like this:

if( $user->possibleActivities()->contains( $activity ) ){
    $user->activity()->associate($activity);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM