Reputation: 358
So I`m trying to create a search filter.
And i have created this:
$data = Input::all();
$ads = new Ads();
if($data['description']) {
$ads = $ads->where('description', 'LIKE', '%' . $data['description'] . '%');
}
if($data['min']) {
$ads = $ads->where('price', '>', $data['min']);
}
if($data['max']) {
$ads = $ads->where('price', '<', $data['max']);
}
And I have $data['city']. But the problem is that $ads dont have a city, it has userID and every user has its city. How would i do something like this but it would actualy search the user that owns this ad and check if the city is like the searched one.
I tried somthing like this:
$resultAds = $ads;
if($data['city']) {
foreach($resultAds as $rAds) {
if($rAds->compareCity($data['city'])) {
$resultAds[] = $rAds;
}
}
}
$resultAds = $resultAds->paginate(12);
But that dosnt work. It gives this error: Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR) Call to a member function compareCity() on a non-object And $rAds is for somereason boolean? I think thats becouse i havent done the ->get(); but i cannot do that becouse i would like to paginate the results.
Thanks for help.
So now my problem is to create a realationship to get city field out of users table.
id
description
price
userID
id
username
password
phone
city
I need to make a releationship so i could get all the ads with the requested city based on what city has the user with the userID taken from ads table.
Upvotes: 0
Views: 104
Reputation: 606
If the ad to user is a belongsTo relationship, then you don't need a table or even to setup a relationship just to filter on city field from users table. You can do a join on the users table. I am assuming your user table is called users:
if($data['city']) {
$ads = $ads->join('users', 'users.id', '=', 'city.userID')
->where('users.city','like','%'.$data['city'].'%');
}
The advantage of a join over whereHas is that it has no subquery that is executed against every row of the ads table, making it more efficient. Additionally, if you always join the users table, whether there is a filter on city or not, then you can pull the city from the users into the ads without having to do additional queries or with() relationships. Like this:
$ads = $ads->join('users', 'users.id', '=', 'city.userID')
if($data['city']) {
$ads = $ads->where('users.city','like','%'.$data['city'].'%');
}
later:
$result = $ads->get(['ads.*', (new Illuminate\Database\Query\Expression('users.city')]);
or if you are going to paginate the result:
$result = $ads->paginate($pageSize, [
'ads.*',
(new Illuminate\Database\Query\Expression('users.city'))
]);
every $ad
that is in the $result
will have a $ad->city
field.
Upvotes: 1
Reputation: 358
So the answer is like this:
if($data['city']) {
$ads = $ads->whereHas('users', function ($q) use($data) {
$q->where('city','LIKE','%'.$data['city'].'%');
});
}
This is the solution that worked. It is kinda taken from the other answer.
And I needed to add this in the model:
public function users() {
return $this->belongsTo('User');
}
And now it works. Thanks everyone for help!
Upvotes: 0
Reputation: 33118
You would want to use whereHas as long as your relationship methods are setup correctly.
if($data['city'])
{
$ads->whereHas('users', function($q) use ($data)
{
$q->where('city', $data['city']);
});
}
Upvotes: 1