问题
This is my controller
$term = $request->get('q');
// return $request->q;
$products = Post::whereHas('user', function($query) use($term) {
$query->where('name', 'like', '%'.$term.'%');
})->orWhere('tags','LIKE','%'.$term.'%')->get();
return view('pages.search', compact('products','users'));
This is working good for single keyword search. But I want to use it for multiple keywords. Like laravel php etc. Please guide me when I search multiple values like abc php laravel or anything then it should work. If tags exists in different column like php is present in 1st column and laravel is in next column when I search php laravel then it should show me both column values.
回答1:
There is probably a better way to do this, like using CloudSearch/Algolia, but this is a solution that has worked for us:
// Split the terms by word.
$terms = explode(" ", request('q'));
$products = Post::query()
->whereHas('user', function ($query) use ($terms) {
foreach ($terms as $term) {
// Loop over the terms and do a search for each.
$query->where('name', 'like', '%' . $term . '%');
}
})
->orWhere(function ($query) use ($terms) {
foreach ($terms as $term) {
$query->where('tags', 'like', '%' . $term . '%');
}
})
->get();
回答2:
You need to prepare the $terms
array first, then just iterate over it and add orWhere()
clauses.
I've just tested it and for whereHas()
closure you need to use where()
for the first term and orWhere()
for the rest of it to make it work:
$posts = Post::whereHas('user', function($q) use($terms) {
$q->where('name', 'like', '%' . $term .'%');
foreach (array_slice($terms, 1) as $term) {
$q->orWhere('name', 'like', '%' . $term .'%');
}
});
foreach ($terms as $term) {
$posts->orWhere('tags', 'like', '%' . $term . '%');
}
$posts = $posts->get();
If you'll decide to use =
instead of like
, just use whereIn()
instead of building query with a bunch of orWhere()
.
回答3:
I spent lots of time on this over the past couple days, and here is my solution. It's similar to these other ones but different, so it may be of value for someone one day:
I have a Vue component that makes a GET request, so $request->get('searchTerms')
comes from <input name="searchTerms">
in the HTML form submit.
I wanted to allow to user to control which fields were going to be searched, so that's why $search_terms
is an array of columns to search.
I wanted it so if the user searched for "McDonalds 604" that it would filter the list of records and show two different matches for that search. One matching "McDonalds" for business_name
and one matching "604" for the area code of the phone_number
. This would ensure the user would get everything related in case they only knew some fragments.
The goal was to iterate over the search terms and also to iterate over the search fields (columns) with a generic formula that could be applied from any number of search terms and columns, dynamic at runtime.
$search_fields = ['project_name', 'business_name', 'phone_number'];
$search_terms = explode(' ', $request->get('searchTerms'));
$query = Campaign::query();
foreach ($search_terms as $term) {
$query->orWhere(function ($query) use ($search_fields, $term) {
foreach ($search_fields as $field) {
$query->orWhere($field, 'LIKE', '%' . $term . '%');
}
});
}
$filtered = $query->get();
I would recommend reading through the query docs for Laravel because it will give you better intuition about this task: https://laravel.com/docs/5.6/queries
In the above code, we are using parameter grouping
and it changes the characteristics of the algorithm if you use where
vs. orWhere
.
Bonus Factoids
I also highly recommend testing your SQL statements using $query->toSql()
and $query->getBindings()
. You can put those in place of $query->get()
to see what the SQL statement it is generating will look like and what the parameter bindings are. getBindings()
will show you what the values of the ?
are in toSql()
.
来源:https://stackoverflow.com/questions/46766843/how-can-i-search-multiple-keywords-in-laravel