Take this working code. It firstly searches the users table for a keyword and then it will use the whereHas() method to search the pivot table category_user for any users assigned to a given category based on a search. This works nicely, all entries are retrieved.
So to be absolutely clear 3 tables are in use, users, categories and category_user.
I am using Laravel collections sortByDesc() to order the entries based on relevance. So if category 1, category 2 and a keyword of my example search term were all stored against user 1 and only category 1 was stored against user 2, user 1 would display first in the results.
The below code does exactly this but ONLY on the users table. I Have had a good scan around and cannot seem a way to work this solution into this type of query, due to the uniqueness of the way I need to order. Can anyone advise any methods?
//props for sortByDesc
$props = ['name', 'slug', 'location', 'company_name', 'biography', 'usually_active'];
//Search Query
//1. Search users table for keywords
//2. use whereHas() to search pivot table of categories for keyword and filters selected
//3. use sortByDesc collections to order results based number of matches, most matches ordered at the top
$search_results = User::where('approved', '=', 1)
->where('user_type_id', '=', 1)
->orWhere(function ($q) use ($search_items) {
//search users tables
foreach ($search_items as $value) {
$q->orWhere('name', 'like', "%{$value}%");
$q->orWhere('location', 'like', "%{$value}%");
$q->orWhere('company_name', 'like', "%{$value}%");
$q->orWhere('biography', 'like', "%{$value}%");
$q->orWhere('usually_active', 'like', "%{$value}%");
}
})->whereHas('categories', function ($q) use($search_items) {
//search categories table
if(!empty($search_items)):
$q->whereIn('name', $search_items);
$q->orWhereIn('slug', $search_items);
endif;
//Now we sort based on best matches
})->get()->sortByDesc(function($i, $k) use ($search_items, $props) {
// The bigger the weight, the higher the record
$weight = 0;
// Iterate through search terms
foreach($search_items as $item) {
foreach($props as $prop) {
if(strpos($i->{$prop}, $item) !== false)
$weight += 1; // Increase weight if the search term is found
}
}
return $weight;
});
//get the results and paginate
$search_results = $search_results->values()->all();
$search_results = $this->paginate($search_results);