laravel-scout-tntsearch-driver
laravel-scout-tntsearch-driver copied to clipboard
Using laravel-scout tntsearch along with eloquent query builder
Hi everybody, I want the user to sort, filter AND tnt-search Model entries, in my laravel backend I have a search method API call, currently I can't get scout's Model::search method to work along with Eloquent's query builder, so you either:
- Search by text if request has 'search'.
- Sort or filter with eloquent query builder (see link bellow for more info).
How can I get both the results from tnt-search term search and eloquent query builder to return a merged result, paginated;
My search method:
public function search(Request $request, QueryFilters $filters)
{
if($request->has('search'))
{
$posts = Post::search($request->input('search'))->paginate(10);
$posts->load(['postcategory','author','favorites']);
if($posts->isEmpty())
{
return response()->json([
'message' => 'No se encontraron resultados',
],500);
}
return response()->json([
'message' => 'Encontramos unas coincidencias',
'posts' => $posts,
], 200);
}
else
{
$posts = Post::filter($filters)->with(['postcategory','author','favorites'])->paginate(10);
if($posts->isEmpty())
{
return response()->json([
'message' => 'No se encontraron resultados',
],500);
}
return response()->json([
'message' => 'Encontramos unas coincidencias',
'posts' => $posts,
], 200);
}
}
And in case you are wondering what does Model::filter do, it just iterates through the request query params and uses Eloquent to sort and filter, you can check this medium article:
https://medium.com/@mykeels/writing-clean-composable-eloquent-filters-edd242c82cc8
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
class QueryFilters
{
protected $request;
protected $builder;
public function __construct(Request $request)
{
$this->request = $request;
}
public function title($term)
{
$lowerCaseTerm = strtolower($term);
return $this->builder->where('title', 'LIKE', "%$lowerCaseTerm%");
}
public function apply(Builder $builder)
{
$this->builder = $builder;
foreach ($this->filters() as $name => $value)
{
//if method doesn't exists continue out of the loop
if ( ! method_exists($this, $name))
{
continue;
}
//method exists so check if it has a value payload so call the method with arguments
if (strlen($value))
{
$this->$name($value);
}
//it doesn't have a payload so call the method without arguments
else
{
$this->$name();
}
}
return $this->builder;
}
public function filters()
{
//returns associative array of request body key value pairs
return $this->request->all();
}
}
I went through this same problem. The search method returns a ScoutBuilder object, which is incompatible with the EloquentBuilder object. So I retrieve the search results first, and append those results to my eloquent query:
$keyword = 'something';
$query = Model::query();
$searchQuery = Model::search($keyword);
$query->whereIn('id', $searchQuery->keys()->toArray());
Seems to get the job done.