Jesse Luke Orange
Jesse Luke Orange

Reputation: 1999

Highlighting search results when using Laravel Scout

In my application, I am using Laravel Scout with the TNTSearch Driver to create a search bar in my site navigation, which is connected to a search method.

The search method searches a bunch of different models and returns what it finds to a view.

Here is the method:

/**
 * Perform a search given what the user entered into the search box.
 * Uses Laravel Scout to do initial search but because the use of WHERE is limited,
 * we use a filter function instead, on each collection.
 *
 * @param Request $request
 * @return void
 */
public function search(Request $request)
{
    // The search string entered
    $search = $request->get('q');

    // Laravel Scout search() method
    $users = User::search($search)->get();
    $articles = Article::search($search)->get();
    $events = Event::search($search)->get();
    $files = FileMetaData::search($search)->get();

    // The date and time as of right now
    $today = Carbon::now();

    /**
     * Below are the filters in place for each model search
     * 1. News articles must be open
     * 2. \Events are split into open and closed
     */
    $articles = $articles->filter(function ($articles) {
        return $articles->published === 'published';
    });

    $upcomingEvents = $events->filter(function ($events) use ($today) {
        return $events->startDate->gt($today);
    });

    $pastEvents = $events->filter(function ($events) use ($today) {
        return $events->startDate->lt($today);
    });

    $userCount = count($users);
    $articleCount = count($articles);
    $eventCount = count($events);
    $upcomingEventCount = count($upcomingEvents);
    $pastEventCount = count($pastEvents);
    $fileCount = count($files);

    return view('pages.search.index', compact('search', 'users', 'articles', 'upcomingEvents', 'pastEvents', 'userCount', 'articleCount', 'upcomingEventCount', 'pastEventCount', 'files', 'fileCount'));
}

As you can see, I'm using Scout's search() function to search each model and then put some additional constraints on the results, before returning them to my view.

The view itself

enter image description here

I would like the highlighted text at the top to also highlight where appropriate with the search results themselves but I can't seem to find anything in the documentation about using the TNT Highlighter class with Laravel.

Trawling through Laracasts forums, I found this: https://laracasts.com/discuss/channels/laravel/algolia-highlighting-in-laravel-53?page=1

Point of interest

<?php

use TeamTNT\TNTSearch\TNTSearch;

$articles = Article::search($searchString)->get();
$tnt = new TNTSearch;

$articles = $articles->map(function($article) use ($searchString, $tnt) {
    $article->title = $tnt->highlight($title, $searchString, 'em'),
});

In my case would I need this snippet for each result set?

An update:

$articles = Article::search($search)->get();

/**
     * Declaire where highlighting should occur for each collection
     */

    // Articles
    $articles = $articles->map(function($article) use ($search, $tnt){
        $article->title = $tnt->highlight($article->title, $search, b, [
            'simple' => false,
            'wholeWord' => false, 
            'tagOptions' => [
                'class' => 'search-term',
                'title' => 'test'
            ]
        ]);

        return $article;
    });

Upvotes: 1

Views: 2591

Answers (2)

Good solution:

public function getTitle($q = null)
{
    if (!$q) {
        return $this->__get('title');
    } else {
        return preg_replace("/($q)/i", '<em>$1</em>', $this->__get('title'));
    }
}

Upvotes: 1

JPark
JPark

Reputation: 789

I'm not familiar with the TNT highlighter, but if you wanted to try your own approach, you could use something like this:

/**
* @$str = The string to highlight
* @$search_term = The term we are looking for in $str
**/
function highlightString($str, $search_term) {
    if (empty($search_term))
        return $str;

    $pos = strpos(strtolower($str), strtolower($search_term));

    if ($pos !== false) {
        $replaced = substr($str, 0, $pos);
        $replaced .= '<em>' . substr($str, $pos, strlen($search_term)) . '</em>';
        $replaced .= substr($str, $pos + strlen($search_term));
    } else {
        $replaced = $str;
    }

    return $replaced;
}

Just don't forget to style the <em> tag

Upvotes: 3

Related Questions