Create a Searchable Model

With Laraloop you can create a searchable Model which can be aggregated in autocomplete and in search controller, or also be searchable separately. Below are explained how to do this manually or using Code Generator.

This is a customized version of package spatie/laravel-searchable, which you can find here. Has all features of this package plus a few custom to handle better Laraloop specific requirements such as different result in admin and frontend, pagination and fuzzy search (ngrams). More about below.

1. Implement Searchable

Your Model must implement Laraloop\Laraloop\Search\Searchable with the method getSearchResult() . Example:


namespace App\Models;

use Illuminate\Database\Eloquent\Model as Model;
use Laraloop\Laraloop\Search\Searchable;
use Laraloop\Laraloop\Search\SearchResult;

/**
 * Class Post
 */
class Post extends Model implements Searchable
{
    /**
     * @var array
     */
    public function getSearchResult($isAdmin = false): SearchResult
    {
        $title = $this->title;
        $body = $isAdmin ? "{$this->slug} {$this->content}" : "{$this->content}";
        $url = $isAdmin ? route('admin.posts.show', $this) : route('posts.show', $this->slug);
        $cover = $this->getCover();

        return new SearchResult($this, $title, $body, $url, $cover);
    }
}

The method getSearchResult has a param that is true or false, which can be used to return different result for admin or frontend. This is useful for hide for example email in search result in frontend while allow to show in admin, or for return different URL depending if admin or frontend.

In case you don't have an image for a model, you can return an icon using:

<div class="tile tile-sm bg-muted"><i class="fas fa-table"></i></div>

2. Aggregate searchable model for admin and/or frontend

For enable searchable model aggregated with others searchable model, you can define in admin and/or frontend config like below example:

    'search_aggregator' => [
        'users' => [
            'class' => 'Laraloop\Laraloop\Models\User', // Models class name
            'attributes' => ['name', 'username', 'email'] // [array of searchable attributes]
        ],
        'posts' => [
            'class' => 'App\Models\Post', // Models class name
            'attributes' => ['title', 'slug', 'content'] // [array of searchable attributes]
        ],
    ],

3. Custom Search implementation

Above steps allow you already to have fully functional and aggregated search results both in autocomplete or in search page of admin. You can also create a custom search depending on your need. Before continue read the basic usage explained here.

Laraloop has a custom service class named SearchService which allow to implement custom searching for any model, via autocomplete or normal search.

Usage in a controller for retrieve all posts which match value from request:

    /**
     * @param Request $request
     * @param SearchService $searchService
     */
    public function postsSearch(Request $request, SearchService $searchService)
    {
        $searchResults = $searchService->isNotAdmin()->disablePagination()->performSearch($request->search, 'posts');
    }

You have several other method in SearchService such as:

// Per page when using pagination
$perPage = 50;

// Query value to search
$query = $request->search;

// key defined in config('search_aggregator');
$resources = 'posts'; 
// or pass custom model or models not defined in config using:
$resources['posts'] = [
  'class' => 'App\Models\Post', 
  'attributes' => ['title', 'slug', 'content']
];

// Enable search in admin with pagination
$searchService = $searchService->isAdmin()->enablePagination($perPage);

// Perfom search
$searchResults = $searchService->performSearch($query, $resources);

// Perfom search for autocomplete
$searchResults = $searchService->autocomplete($query, $resources);

// Perfom search with fuzzy search enabled
$searchResults = $searchService->performFuzzySearch($query, $resources);

For display result you can use as explained in package spatie/laravel-searchable:

@foreach($searchResults->groupByType() as $type => $modelSearchResults)
    @foreach($modelSearchResults as $row)
        <!-- access full model attributes using $row->searchable -->
        <div class="list-group-item js-grid-item">
            <a href="{{ $row->url }}" class="stretched-link"></a>
            <div class="list-group-item-figure">
                {!! $row->picture !!}
            </div>
            <div class="list-group-item-body">
                <h4 class="list-group-item-title">{{ $row->title }}</h4>
                <p class="list-group-item-text">{{ $row->body }}</p>
            </div>
        </div>
    @endforeach
@endforeach