Laravel 5.8: orWhere anulls the whereHas effect - laravel

I'm trying to do a simple search function. For that, I implemented the following query:
Profile::whereHas('accounts', function ($query) use ($id) {
$query->where('user_id', $id);
})
->where('username', 'LIKE', "%{$search}%")
->paginate(20);
The whereHas selects the profiles that the user with $id has.
Then, with the where we figure out if the search match with some username in the database.
Finally, we paginate the results.
All right so far.
The problem comes when I add a orWhere like that:
Profile::whereHas('accounts', function ($query) use ($id) {
$query->where('user_id', $id);
})
->where('username', 'LIKE', "%{$search}%")
->orWhere('fullname', 'LIKE', "%{$search}%")
->paginate(20);
I want that the query analyses if the search matchs with the username and/or the fullname. When I add the orWhere works, but the whereHas doesn't do its work and the results are from all the users.

You need to do it like this:
Profile::whereHas('accounts', function ($query) use ($id) {
$query->where('user_id', $id);
})
->where(function($query) use ($search) {
$query->where('username', 'LIKE', "%{$search}%")
->orWhere('fullname', 'LIKE', "%{$search}%");
})
->paginate(20);

Related

Laravel Query Through Relationship

I am creating a search in laravel where customers can search for vehicles.
Table 1
Vehicle
VIN
PLATE
make_and_model_id
Table 2
Vehicle Makes and Models
id
make
model
Relationship in Table 1: Vehicle
public function vehicle_make_and_model_fk()
{
return $this->belongsTo('App\Models\VehicleMakeAndModel', 'vehicle_make_and_model_id');
}
So I am searching for VIN or Plate. That works fine.
I also am Searching for a Make and Model name which is a foreign key.
I pulled in the related table using with which works fine.
Now how to search through the columns of Make and Model Table?
if($request->ajax()) {
$search = $request->search_query;
$vehicles = Vehicle::with('vehicle_make_and_model_fk')
->where(function ($query) use ($search) {
$query->where('plate', 'LIKE', '%'.$search.'%')
->orWhere('vin', 'LIKE', '%'.$search.'%')
->orWhere('vehicle_make_and_models.make', 'LIKE', '%'.$search.'%');
})
->limit(5)
->get();
echo json_encode($vehicles);
exit;
}
To filter the relationship, you need to use a closure in your with()
For example:
$vehicles = Vehicle::query()
->with([
'vehicle_make_and_model_fk' => function ($query) use ($search) {
$query->where('make', 'like', "%$search%")
->orWhere('model', 'like', "%$search%");
}
])
->where(function ($query) use ($search) {
$query->where('plate', 'like', "%$search%")
->orWhere('vin', 'like', "%$search%");
})
->limit(5)
->get();
Eloquent Relationships - Constraining Eager Loads
$vehicles = Vehicle::where('plate','LIKE','%'.$search.'%')
->orWhere('vin','LIKE','%'.$search.'%')
->with('vehicle_make_and_model_fk')
->orwhereHas('vehicle_make_and_model_fk',
function($query) use($search){
$query
->where('vehicle_make_and_models.make','like',$search.'%')
->orWhere('vehicle_make_and_models.model','LIKE','%'.$search.'%');
}
)
->limit(5)
->get();
This query worked. It would search and bring results from vehicle table and would go to makes and models table and bring results from there as well. Based on - Laravel Eloquent search inside related table

Laravel - whereHas query not returning correct records

I am currently writing a search query but I'm having issues joining a where with a whereHas
if I wanna search for categories only..
The below query works if I just search for categories solo
$goals = $myGoals
->whereHas('categories', function ($q) use ($search) {
$q->where('name', 'like', "%$search%");
})->paginate(10);
if I wanna search for the title only..
Same as above if I wanna search for the title of goals solo
$goals = $myGoals->where('title', 'like', "%$search%" )->paginate(10);
both of the queries work if I want to search for them individually.
Query attempt
Below is the query I've written to allow a user to search for the title of a goal and the name of a category.
$myGoals = $team->goals();
$goals = $myGoals
->whereHas('categories', function ($q) use ($search) {
$q->where('name', 'like', "%$search%");
})->where('title', 'like', "%$search%" )->paginate(10);
I have tried the above query but the search results return empty when I enter an input. I've also tried swapping the where() to orWhere() which then returns a goal that doesn't belong to the $team model instance but it's a goal record linking to a different Team model id within the pivot table.
Can anyone spot where I am going wrong? thanks
You need to use it all inside where.
$goals = $myGoals->where(function ($query) use ($search){
return $query->whereHas('categories', function ($q) use ($search) {
$q->where('name', 'like', "%$search%");
})->orWhere('title', 'like', "%$search%" );
})->paginate(10);

Why doesn't my Laravel conditional whereHas query work?

I am trying to create a conditional User search function. There are three filters that a user could select to search on:
user name
company name associated with user
role name associated with user
In the following example I have put all the filters in the array $searchFilters for simplicity.
I only want Laravel to search the filters that are present in the array.
The code
$q = request()->q;
$searchWildcard = '%' . $q . '%';
$searchFilters = ['name', 'roles', 'company'];
$users = User::when(in_array('roles', $searchFilters), function ($query) use ($searchWildcard) {
$query->whereHas('roles', function($query) use ($searchWildcard) {
$query->where('name', 'LIKE', $searchWildcard);
});
})->when(in_array('company', $searchFilters), function($query) use ($searchWildcard) {
$query->whereHas('company', function($query) use ($searchWildcard) {
$query->orWhere('name', 'LIKE', $searchWildcard);
});
})->when(in_array('name', $searchFilters), function($query) use ($searchWildcard) {
$query->orWhere('name', 'LIKE', $searchWildcard);
});
The first part of the query works: It retrieves the roles based on the search query by the user, but it doesn't work for the company name or user name.
Edit
It only doesn't work for the company name.
You orWhere condition is inside another where so I imagine it won't work as expected.
I would suggest changing your whereHas to orWhereHas and then changing the orWhere inside it to where:
$users = User::when(in_array('roles', $searchFilters), function ($query) use ($searchWildcard) {
$query->whereHas('roles', function ($query) use ($searchWildcard) {
$query->where('name', 'LIKE', $searchWildcard);
});
})->when(in_array('company', $searchFilters), function ($query) use ($searchWildcard) {
$query->orWhereHas('company', function ($query) use ($searchWildcard) {
$query->where('name', 'LIKE', $searchWildcard);
});
})->when(in_array('name', $searchFilters), function ($query) use ($searchWildcard) {
$query->orWhere('name', 'LIKE', $searchWildcard);
});

Constrain which relationship models are returned on whereHas

An example from the documentation:
$posts = App\Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
This will look for posts that has at least one comment with foo. It will return the post model with all comments. Is there a way to restrict this to return post model and related comments that only have foo?
I'm aware we can loop through $posts with a conditional later on but I'm looking for a solution via the query builder if possible.
From the docs:
https://laravel.com/docs/5.7/eloquent-relationships#constraining-eager-loads
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
Edit, the other answer is correct.. you should add it to you actual query, not just replace it as i suggested first:
So, from your example it would look like this:
$posts = App\Post::with('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
You could also just add a lazy loading after your query
$posts->load(['comments' => function ($query) {
$query->where('content', 'like', 'foo%');
}]);
Edit, solution suggested by #HelenChe (original asker), it's basically the same, useful if with and wherehas are going to have the same filter function.
$posts = Post::whereHas('comments', $filter = function ($query) {
$query->where('content', 'like', 'foo%');
})->with(['comments' => $filter])->get();
If you want only the posts that has at least one comment with foo with those comments. you have to combine these two function, whereHas() and with()
$posts = App\Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
->with('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();

How to use where conditional in with Laravel?

I do request using query:
return Baber::where(function ($query) use ($request) {
// HERE CONDITION WHERE FOR USER TABLE
})->with("user")->orderBy('id', 'desc')->get();
How can I use where() inside query, that it will be comparabled with user table in with("user")?
I mean the following:
return Baber::where(function ($query) use ($request) {
$query->where('user.created_at', $request->date);
})->with("user")->orderBy('id', 'desc')->get();
It's known as constraining eager loads.
Baber::with(['user' => function ($query) use ($request) {
$query->where('user.created_at', '=', $request->date);
}])
->orderBy('id', 'desc')
->get();

Resources