I have users and roles relationship as belongsToMany.
I now want to get all users have multiple roles by names.
I have tried as,
$role_ids = [1,2];
$users = User::whereHas('roles' , function ($query) use($role_ids) {
$query->whereIn('roles.id', $role_ids);
})->get();
But this approach gives me users who are associated with both or either one roles which is not i am expecting
You'll have to add multiple whereHas for that:
$role_ids = [1,2];
$users = User::with('roles');
foreach($role_ids as $role){
$users->whereHas('roles', function($q) use ($role){
$q->where('roles.id', $role);
});
}
$users = $users->get();
Related
I have a Prize, Ticket and User model. A prize can have many tickets, and a ticket can only be associated to one User.
Each Prize will have one Winning Ticket, what I am trying to do is list all my Users that have a winning Ticket like so:
$winning_tickets = Prize::WinnerSelected()->get('ticket_winner_id')->pluck('ticket_winner_id');
$users = User::with(['tickets' => function($query) use ($winning_tickets) {
$query->whereIn('id', $winning_tickets);
}])->get();
$winning_tickets returns an array of winning ticket ids, but the $users collection returns ALL my users, even users that have no ticket records.
Can anyone explain what I am doing wrong?
with() doesn't actually filter the User Collection being returned. To do that, you need to use whereHas():
$winningTickets = Prize::WinnerSelected()->get('ticket_winner_id')->pluck('ticket_winner_id');
$users = User::whereHas('tickets', function($query) use ($winningTickets) {
$query->whereIn('id', $winningTickets);
})->get();
Now, the $users Collection will only contain User records that have one or more Ticket records matching the given ticket_winner_id in $winning_tickets.
If you need to, you can use both with() and whereHas() to filter and eager load the associated Ticket records:
$winningTickets = Prize::WinnerSelected()->get('ticket_winner_id')->pluck('ticket_winner_id');
$filterClause = function ($query) use ($winningTickets) {
return $query->whereIn('id', $winningTickets);
};
$users = User::with(['tickets' => $filterClause])
->whereHas('tickets', $filterClause)
->get();
Define the the function ($query) as a reusable clause to avoid repetition, and voila!
Sidenote, you don't need to chain ->get() into ->pluck(); both Builder and Collection classes have a ->pluck() method, so this is valid:
$winningTickets = Prize::WinnerSelected()->pluck('ticket_winner_id');
I have 3 tables: User, Role and the pivot table RoleUser with role_id and user_id.
For the relations in my models i did that :
Role Model :
public function users() {
return $this->belongsToMany('App\Models\User')->using(RoleUser::class);
}
User Model:
public function roles() {
return $this->hasMany('App\Models\Role')->using(RoleUser::class);
}
I did that for filter by one role and it works well :
$roles = Role::find($request->get('role_id'))->first();
return $roles->users;
But now i need to filter my users by many roles.
I ll send an array from my front-end with id's of the roles.
Actually i'm able to get the roles like below
$roles = Role::whereIn('id', $request->get('role_id'))->get();
$roles = [{"id":2,"name":"Admin","description":"blabla","created_at":"2018-12-04 09:48:56","updated_at":"2021-04-23 14:53:15"},{"id":3,"name":"developper","description":"blabla","created_at":"2018-12-04 09:51:31","updated_at":"2021-04-23 14:53:15"}]
But i dont know how can i get the users with this roles.
You need to go through the collection and get each role's users and return them in one array as shown below:
$roles = Role::whereIn('id', $request->get('role_id'))->get();
return $roles->map->users->flatten();
Or you do it the other way round:
return User::whereHas('roles', function($q) use($request) {
$q->whereIn('id', $request->get('role_id'));
})->get();
Let's say I have the relation: Role has many Users. Role and user stores a code value.
If I want to select all roles that have users with same code, how would be this query using whereHas clause?
What I tried:
$roles = Role::whereHas('users', function ($users) {
// Obviously doesn't work but it is what I need to access.
$code = $users->first()
->role
->code;
return $users->where('code', $code);
})->get();
Use this:
$roles = Role::whereHas('users', function ($query) {
$query->whereColumn('users.code', 'roles.code');
})->get();
A User has many Phones. I want to get all the phones from active users. I can do:
$phones = [];
$users = User::with('phones')->where('active', 1)->get();
foreach($users as $user) {
$phones = array_merge($phones, $user->phones->toArray());
}
dd($phones); // <- Here are all the phones.
But I'm not sure it's the more elegant or laravel-ish way. Is there a built in magic function for such a case? Can I get all the phones from active users without writing a loop and insert in an Array?
You should use whereHas() method:
$phones = Phone::whereHas('user', function($q) {
$q->where('active', 1);
})->get();
You can also use whereExists, which can be more efficient if you're not using data from the users table:
Phone::whereExists(function($query) {
$query->select(\DB::raw('NULL'))
->from('users')
->whereRaw('users.id = phones.user_id AND users.active = 1')
})->get();
In my Laravel app, I have the concept of users, friends, and groups. A user can create and sort friends into groups.
A user can have many friends:
function friendsOfMine()
{
return $this->belongsToMany('App\User', 'helpers', 'user_id', 'helper_id')
->wherePivot('accepted', '=', 1);
}
A group can have many users:
public function groupMembers()
{
return $this->belongstoMany('App\User')->withTimestamps();
}
In the UI for adding friends to a group, I want to show the full list of a user's friends, but exclude those friends that have already been added to the group. My Groups Controller function looks like this, though I'm positive I'm off-base.
public function add($id)
{
$group = Group::findOrFail($id);
$helpers = $group->groupMembers;
$id = $helpers->lists('id');
$invitees = $this->user
->friendsOfMine()
->where('helper_id', '!=', $id)
->Paginate(5);
return view('groups.add', compact('group','helpers','invitees'));
}
Ideally, what I'd love is some way to write:
$helper = $group->friendsOfMine->not->groupMembers->Paginate(5);
Is there anyway to filter data using functions from two different models?
With your approach you would have to use whereNotIn() since you have an array of ids:
$id = $helpers->lists('id');
$invitees = $this->user
->friendsOfMine()
->whereNotIn('helper_id', $id)
->Paginate(5);
However you probably could something like this as well (assuming the relation group)
$invitees = $this->user
->friendsOfMine()
->whereDoesntHave('group', function($q) use ($id){
$q->where('group_id', $id); // Note that id is the group id (not the array of ids from the helper)
})
->Paginate(5);
For a nicer syntax (like in your example) you should look into Query Scopes