0

I have defined a users table, a roles table and a user_role pivot in my database. The model for the user is as follows:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    //... Fields defined here

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'user_role');
    }
}

Inside the role model, I have this also:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    //... Fields defined here
    public function users()
    {
        return $this->belongsToMany(User::class, 'user_role');
    }
}

Now here lies the problem. When I run the following in the API routes (relatively crude)

$user_roles = \App\Models\User::with('roles')->get();

I get a list of all the users, with each array having an internal array of all the roles. I will like the results such that each user will have one role and if there are multiple roles, I duplicate the user with this new role.

How is this achieved? Thanks in advance for the assistance

cross19xx
  • 3,170
  • 1
  • 25
  • 40

1 Answers1

1

You can do something like flatMap:

$user_roles = \App\Models\User::with('roles')->get()
   ->flatMap(function ($user) {
      if ($user->roles->isEmpty()) { return $user; }
      return $user->roles->map(function ($role) use ($user) { 
            $newUser = clone $user;
            $newUser->roles = $role;
            return $newUser;
      });
   });

An alternative is to use a join instead of an eloquent relationship e.g.:

$user_roles = DB::table('users')
    ->join('user_role', 'user_role.user_id', 'user.id')
    ->join('roles', 'user_role,role_id', 'roles.id')
    ->selectRaw('users.*, roles.*')->get();

This should result in a result of users and roles combined in one object.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
  • I tried the first option and it worked well. The second one worked also but it seemed to take a noticeably longer time (this was not benchmarked properly, so users beware). – cross19xx Aug 29 '22 at 14:39