Laravel whereHas not working as expected - php

I have a relationship on my User table called 'roles'.
This relationship is:
public function roles()
{
return $this->hasMany('App\RoleUser');
}
I am only trying to fetch users that have a role of 3.
My query is:
User::where('name', $name)
->orWhere('email', $email)
->whereHas('roles', function ($q) {
$q->where('id', 3);
})->get();
This, however, is returning all users no matter what their role. I can confirm that all users have roles and the roles relationship is working.
The fields in the role_user table are 'id', 'user_id'

Looks like this issue was caused by a previous orWhere clause on the query.
Looking at the original query in the question:
User::where('name', $name)
->orWhere('email', $email)
->whereHas('roles', function ($q) {
$q->where('id', 3);
})->get();
This reads as where the name is 'name' and the user has roles and includes a role of 3. The query was also bringing in any results that had an email that matched my provided email but because it was 'orWhere' it ignored the other requirements.

Related

Get datas from relation table (with()) with a condition

I have an 'implementation' table that contains relationships to retrieve projects and scores.
The scores table contains a" user_id "field.
I would like to collect all the implementations but with only the score which contains the user_id.
My original query.
public function getImplementations($id, $student)
{
$data = Implementation::where('event_id', $id)->where('student_id', $student)->with('project', 'score')->get();
return response()->json($data);
}
My test for get only the score from specific user (only one score per user per implementation, so no conflict possible)
$data = Implementation::where('event_id', $id)
->where('student_id', $student)->with('project', 'score')
->whereHas('score', function ($query) {
$query->where('user_id', Auth::user()->id);
})->get();
But that does not give the expected result. This is not the right method and I do not know the right one.
Thanks for your help
I am not sure if there's a need to eager-load and constrain a relationship simultaneously. Does the following provide you with the expected result?
$data = Implementation::where('event_id', $id)
->with([
'project',
'score' => function ($query) {
$query->where('user_id', Auth::id());
}
])
->where('student_id', $student)
->get();

How can I pick single record from one to many relation?

I have one to many relation based two tables users and games and there is also bridge table users_games (linking user_id to games).
I want to fetch a single record from games table based on provided game_id for specific user. I did some research and found whereHas() which is returning all games which are belongs to specific user. But I need to fetch one based on game_id. Can some one kindly let me know how can I fix issue in below script
$GameInfo = User::with('games')->whereHas('games', function ($query) use($request)
{
$query->where('game_id', '=', $request->game_id);
})->find(request()->user()->id);
Is this what you're trying to do?
$GameInfo = $request
->user()
->games()
->where('game_id', $request->game_id)
->first();
try this:
$GameInfo = User::with(['games' => function ($query) use($request)
{
$query->where('game_id', $request->game_id);
}])->whereHas('games', function ($query) use($request)
{
$query->where('game_id', '=', $request->game_id);
})->find(request()->user()->id);
If your relation 'games' is a hasMany() with table 'users_games', You can try this code
$GameInfo = User::with(['games' => function ($query) use($request)
{
$query->where('game_id', $request->game_id);
}])
->where('users.id', <user_id_variable>)
->first();
And the relation 'games' in User Model as
public function games()
{
return $this->hasMany('App\Models\UserGames', 'user_id', 'id');
}

Laravel : if record not found then search relational model

I am trying to find a record in User model , if the record doesn't exists in User model, Then find it in UserCompany model with relation name company in User model.
$companyUser = \App\User::whereHas('company', function ($query) use ($request) {
$query->where('company_email', '=', $request->email);
})->where('email', $request->email)->get();
I am getting empty set there, What am i missing.
You can do like this,
$companyUser = \App\User::where('email', $request->email)
->orWhereHas('company', function ($query) use ($request) {
$query->where('company_email', '=', $request->email);
})->get();

Get role name for admin user

I have table for admin user and its roles with their relations. I want admin user listing with their respective role.
I tried below query
$adminusers = Admin::whereHas('roles', function($q)
{
$q->where('roles.name', '<>', 'Superadmin');
$q->select('roles.name as roles');
})->select('id', 'name')->where('admins.status', 'A')->where('admins.is_delete', '0')->paginate(15);
but i am not able to retrieve role name from it.
So how can i get the role name from above query?
You can't select from a whereHas closure. whereHas in this scenario is used to limit the results of admins, not to retrieve the roles.
You can query a relationship of a specific model like so:
$singleAdmin->roles()->where('roles.name', '<>', 'Superadmin')->get();
Or you can put constraints during eager loading:
Admin:::with(['roles' => function ($query) {
$q->where('roles.name', '<>', 'Superadmin');
}])->get();
https://laravel.com/docs/5.4/eloquent-relationships#constraining-eager-loads
Once eager loaded, you would need to access the collection of roles from $singleAdmin->roles.
In some cases, it makes sense to just use a join.
You can use the leftJoin method.
`$admins = Admin::leftJoin('roles','admin.role_id','=','roles.id')
->select('id', 'name')
->where('admins.status', 'A')
->where('admins.is_delete', '0')
->paginate(15)`
Or you can do it in model file
`public function role()
{
return $this->hasOne(\App\Models\Roles::class, 'id', 'role_id');
}`

Retrieve models that belongsToMany specific models

I've got a standard many-to-many relationship
class User {
public function roles() {
return $this->belongsToMany('Role');
}
}
class Role {
public function users() {
return $this->belongsToMany('User');
}
}
And it works very well.
But I need to select all the users that has exactly two specific roles.
$roleAdmin = Role::where('name', 'admin')->first();
$roleUser = Role::where('name', 'user')->first();
$users = //which users has BOTH $roleAdmin and $roleUser ??
Is it possible to achieve this using eloquent or I need a raw query?
PS the use-case is stupid, I know, it's just an abstraction of my real problem (that doesn't concern users and roles)
The best solution I found is to get admins and users and then use intersect() helper to get only users who are present both in $users and admins collections:
$users = User::whereHas('roles', function ($q) use($otherRoles) {
$q->where('name', 'user')->whereNotIn('name', $otherRoles);
})->get();
$admins = User::whereHas('roles', function ($q) use($otherRoles) {
$q->where('name', 'admin')->whereNotIn('name', $otherRoles);
})->get();
$result = $admins->intersect($users);
If you want to save some memory, you could pluck() only IDs, intersect() these and only then get users with whereIn().
This is not an eloquent solution(by all means)
$users = \DB::table('users')
->select(\DB::raw("GROUP_CONCAT(roles.name SEPARATOR '-') as `role_names`"), 'users.name')
->join('role_user', 'users.id', '=', 'role_user.user_id')
->join('roles', 'roles.id', '=', 'role_user.role_id')
->groupBy('users.id')
->having('role_names', '=', 'admin-user')
->get();
admin-user can be user-admin, which roles names comes first in the database. Please change table and column names as per your requirement

Categories