iamdannygreen's avatar

Has Many Through Relationship with Many to many?

I'm setting up simple Roles/Permissions for an application I am building. Roles are attached to the user with a many to many relationship using a pivot table, and permissions are attached to roles again using a pivot table. What I would like to do is check if a user has a certain permission, however this means accessing the Permission model via the roles. I have seen a possible solution using a 'has many through' relationship, however I believe this can't be used with many to many relationships?

Any advice would be greatly appreciated.

In the User Model

public function roles()
 {
        return $this->belongsToMany('App\role')->withTimestamps();
}

Role Model

class role extends Model
{
    public function users()
    {
        return $this->belongsToMany('App\User')->withTimestamps();
    }

    public function permissions()
    {
        return $this->belongsToMany('App\Permission')->withTimestamps();
    }
}

Permission Model

class Permission extends Model
{
    public function roles()
    {
        return $this->belongsToMany('App\Role')->withTimestamps();
    }
}
0 likes
2 replies
tylernathanreed's avatar
Level 14

I've dealt with this in the past. Here's my solution:

User Model

public function permissions()
{
    // Determine the Roles associated with this User
    $roles = $this->roles()->with('permissions')->get(); // Use Eager Loading for Faster Results

    // Determine the Permissions associated with the Roles
    $permissions = $roles->pluck('permissions'); // Plucked from Eager Loading

    // Turn the Collection of Collections into a Single Collection
    $permissions = call_user_func_array('array_merge', $permissions->toArray());

    // Pluck the IDs from the Permissions
    $ids = array_column($permissions, 'id');

    // Remove Duplicate IDs
    $ids = array_unique($ids);

    // Return the Permissions associated with this User
    return Permission::whereIn('id', $ids);
}

public function getPermissionsAttribute()
{
    return $this->permissions()->get();
}

Permission Model

public function users()
{
    // Determine the Roles associated with this Permission
    $roles = $this->roles()->with('users')->get(); // Use Eager Loading for Faster Results

    // Determine the Users associated with the Roles
    $users = $roles->pluck('users'); // Plucked from Eager Loading

    // Turn the Collection of Collections into a Single Collection
    $users = call_user_func_array('array_merge', $users->toArray());

    // Pluck the IDs from the Users
    $ids = array_column($users, 'id');

    // Remove Duplicate IDs
    $ids = array_unique($ids);

    // Return the Users associated with this Permission
    return User::whereIn('id', $ids);
}

public function getUsersAttribute()
{
    return $this->users()->get();
}

I do think that having a belongsToManyThroughMany relationship would be nice to have.

Please or to participate in this conversation.