Search code examples
laraveleloquentgraphqllaravel-lighthouse

Eloquent team-based roles


I have 3 tables: Roles, Teams, Users with a pivot table between each: role_team, role_user, team_user.

I'm having a hard time leveraging Eloquent to return only the roles that a user has for a specific team.

$team = Team::find(1);
foreach($team->users as $user) {
    dump($user->teamRoles); // Get the roles this user has for the team
}

While I could do $user->roles()->where('team_id', $team->id)->get(), I'd like to specify it as a relationship. I tried setting up a hasManyThrough, but it doesn't seem to work in this specific case.

The need to use this as a relationship rather than query is because I'm using Lighthouse PHP for GraphQL and would like to easily be able to query for the roles like:

teams {
  id name 
  users {
    teamPivot {
      roles { id name }
    }
  }
}

Any help leveraging Eloquent to make this happen would be greatly appreciated.


Solution

  • One possible solution, though not necessarily the one I'm looking for is to use the @method directive on a field.

    Imagine the following schema:

    type User {
      id: ID!
      email: String!
      teams: [Team] @belongsToMany
      teamMeta: TeamUser
    }
    
    type Team {
      id: ID!
      name: String!
      users: [User] @belongsToMany
      userMeta: TeamUser
    }
    
    type Role {
      id: ID!
      name: String!
      team: Team @belongsTo
      users: [User] @belongsToMany
    }
    
    type TeamUser {
      user: User!
      team: Team!
      roles: [Role] @method(name: "getTeamRoles")
    }
    

    Where getTeamRoles looks like:

    public function getTeamRoles()
    {
      return $this->user->roles()->where('team_id', $this->team->id)->get();
    }
    

    This configuration will allow the following GraphQL to work as desired:

      users(first: 1, input: { id: 2 }) {
        email teams {
          name userMeta {
            contactedAt
            roles { id name }
          }
        }
      }
    

    This is currently the solution I'm running, but it would be nice to have a "pure" Eloquent answer for this instead of having to write a custom accessor for each relation of this type.