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.