Since Scout\Builder
doesn't support union
. And it would be non trivial to implement union
functionality for all possible search engines supported by Scout.
However, Scout\Builder
provides a query() function to customise the eloquent results query.
This provides kind of an escape hatch, where by scout can be leveraged on one model (out of the two)
public function search($term)
{
$postQuery = Post::query()
->where('some_column', 'like', $term . "%");
$results = Page::search($term)
->query(
fn($query) => $query->union($postQuery)
->orderBy('created_at', 'desc')
)
->paginate();
}
Laravel Scout - Customizing the Eloquent Results Query
For Algolia Engine
If using Algolia as search engine, there's Algolia Scout Extended which supports search with multiple models.
For other Engines
Another approach to search multiple models with Scout and get paginated results would be:
- Get search results for individual models using Scout (using
Model::search('query')->get();
)
- Concat the resulting collections
- Paginate the collection
Define a macro for Illuminate\Support\Collection
in the boot
method of a Service Provider (for eg in App\Providers\AppServiceProvider
)
<?php
namespace App\Providers;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\LengthAwarePaginator;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$total ? $this : $this->forPage($page, $perPage)->values(),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
}
}
Then in the controller
public function search($term) {
$post = Post::where('title', 'LIKE', $term)->get();
$page = Page::where('content', 'LIKE', $term)->get();
$result = $page->concat($post)->sortBy('created_at')->paginate(5);
return $result;
}