Laravel Scout is a powerful full-text search package for Laravel applications. It provides an easy-to-use, expressive API for performing full-text searches on Eloquent models. It is powered by the popular open-source search engine, Algolia. With Laravel Scout, you can quickly add full-text search to your Eloquent models. It also provides a simple, driver-based solution for adding full-text search to your application. In this tutorial, we will show you how to use Laravel Scout to enable full-text search in your application.
The Laravel framework has become a go-to resource for developers building web services.
As an open-source tool, Laravel offers a myriad of out-of-the-box functionalities that enable developers to build robust and functional applications.
Among its offerings is Laravel Scout, a library for managing the search indexes for your application. Its flexibility lets developers fine-tune the configurations and select from Algolia, Meilisearch, MySQL, or Postgres drivers to store the indexes.
Here, we will explore this tool in-depth, teaching you how to add full-text search support to a Laravel application through the driver. You will model a demo Laravel application for storing the name of mockup trains and then use Laravel Scout to add a search to the application.
Prerequisites
To follow along, you should have:
- The PHP compiler installed on your computer. This tutorial uses PHP version 8.1.
- The Docker engine or Docker Desktop installed on your computer
- An Algolia cloud account, which you can create for free
How To Install Scout in a Laravel Project
To use Scout, you must first create a Laravel application where you intend to add the search functionality. The Laravel-Scout Bash script contains the commands to generate a Laravel application within a Docker container. Using Docker means you don’t need to install additional supporting software, like a MySQL database.
The Laravel-scout script uses the Bash scripting language, so you must execute it within a Linux environment. If you’re running Windows, ensure you configure Windows Subsystem for Linux (WSL).
If using WSL, execute the following command in your terminal to set your preferred Linux distribution.
wsl -s ubuntu
Next, navigate to the location on your computer you would like to place the project. The Laravel-Scout script will generate a project directory here. In the example below, the Laravel-Scout script would create a directory within the desktop directory.
cd /desktop
Run the command below to execute the Laravel-Scout script. It will scaffold a Dockerized application with the necessary boilerplate code.
curl -s https://laravel.build/laravel-scout-app | bash
After the execution, change your directory using cd laravel-scout-app
. Then, run the sail-up
command within the project folder to start the Docker containers for your application.
Note: On many Linux distributions, you may need to run the command below with the sudo
command to initiate elevated privileges.
./vendor/bin/sail up
You might encounter an error:
To resolve this, use the APP_PORT
variable to specify a port within the sail up
command:
APP_PORT=3001 ./vendor/bin/sail up
Next, execute the command below to run the application through Artisan on the PHP server.
php artisan serve
From your web browser, navigate to the running application at http://127.0.0.1:8000. The application will display the Laravel welcome page at the default route.
How To Add Laravel Scout to the Application
In your terminal, enter the command to enable the Composer PHP package manager to add Laravel Scout to the project.
composer require laravel/scout
Next, publish the Scout configuration file using the vendor:publish command. The command will publish the scout.php
configuration file to your application’s config directory.
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Now, modify the boilerplate .env file to contain a SCOUT_QUEUE
boolean value.
The SCOUT_QUEUE
value will allow Scout to queue operations, providing better response times. Without it, Scout drivers like Meilisearch won’t reflect new records immediately.
SCOUT_QUEUE=true
Also, modify the DB_HOST
variable in the .env file to point to your localhost to use the MySQL database within the Docker containers.
DB_HOST=127.0.0.1
How To Mark a Model and Configure the Index
Scout doesn’t enable searchable data models by default. You must explicitly mark a model as searchable using its Laravel\Scout\Searchable
trait.
You’ll start by creating a data model for a demo Train
application and marking it as searchable.
How To Create a Model
For the Train
application, you’ll want to store the placeholder names of each available train.
Execute the Artisan command below to generate the migration and name it create_trains_table
.
php artisan make:migration create_trains_table
The migration will be generated in a file whose name combines the name specified and the current timestamp.
Open the migration file located in the database/migrations/ directory.
To add a title column, add the following code after the id()
column in line 17. The code will add a title column.
$table->string('title');
To apply the migration, execute the command below.
php artisan migrate
After running the database migrations, create a file named Train.php in the app/Models/ directory.
How To Add the LaravelScoutSearchable Trait
Mark the Train
model for search by adding the Laravel\Scout\Searchable
trait to the model, as shown below.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Train extends Model
{
use Searchable;
public $fillable = ['title'];
Also, you need to configure the search indexes by overriding the searchable
method. The default behavior of Scout would persist the model to match the model table name.
So, add the following code to the Train.php file below the code from the previous block.
/**
* Retrieve the index name for the model.
*
* @return string
*/
public function searchableAs()
{
return 'trains_index';
}
}
How To Use Algolia with Scout
For the first full-text search with Laravel Scout, you’ll use the Algolia driver. Algolia is a software as a service (SaaS) platform used to search through large amounts of data. It provides a web dashboard for developers to manage their search indexes and a robust API that you can access via a software development kit (SDK) in your preferred programming language.
Within the Laravel application, you will use the Algolia client package for PHP.
How To Set Up Algolia
First, you must install the Algolia PHP search client package for your application.
Execute the command below.
composer require algolia/algoliasearch-client-php
Next, you must set your Application ID and Secret API Key credentials from Algolia in the .env file.
Using your web browser, navigate to your Algolia dashboard to obtain the Application ID and Secret API Key credentials.
Click on Settings at the bottom of the left-hand sidebar to navigate to the Settings page.
Next, click API Keys within the Team and Access section of the Settings page to view the keys for your Algolia account.
At the API Keys page, note the Application ID and Admin API Key values. You will use these credentials to authenticate the connection between the Laravel application and Algolia.
Add the code below to your .env file using your code editor and replace the placeholders with the corresponding Algolia API secrets.
ALGOLIA_APP_ID=APPLICATION_ID
ALGOLIA_SECRET=ADMIN_API_KEY
Also, replace the SCOUT_DRIVER
variable with the code below to change the value from meilisearch
to algolia
. Changing this value will instruct Scout to use the Algolia driver.
SCOUT_DRIVER=algolia
How To Create the Application Controllers
Within the app/Http/Controllers/ directory, create a TrainSearchController.php file to store a controller for the application. The controller will list and add data to the Train
model.
Add the following code block into the TrainSearchController.php file to build the controller.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Train;
class TrainSearchController extends Controller
{
/**
* Get the index name for the model.
*
* @return string
*/
public function index(Request $request)
{
if($request->has('titlesearch')){
$trains = Train::search($request->titlesearch)
->paginate(6);
}else{
$trains = Train::paginate(6);
}
return view('Train-search',compact('trains'));
}
/**
* Get the index name for the model.
*
* @return string
*/
public function create(Request $request)
{
$this->validate($request,['title'=>'required']);
$trains = Train::create($request->all());
return back();
}
}
How To Create the Application Routes
In this step, you’ll create the routes for listing and adding new trains to the database.
Open your routes/web.php file and replace the existing code with the block below.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TrainSearchController;
Route::get('/', function () {
return view('welcome');
});
Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists');
Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');
The code above defines two routes in the application. The GET
request for the /trains-lists
route lists all stored train data. The POST
request for the /create-item
route creates new train data.
How To Create the Application Views
Create a file within the resources/views/ directory and name it Train-search.blade.php. The file will display the user interface for the search functionality.
Add the content of the code block below into the Train-search.blade.php file to create a single page for the search functionality.
<!DOCTYPE html>
<html>
<head>
<title>Laravel - Laravel Scout Algolia Search Example</title>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/>
<form method="POST" action="{{ route('create-item') }}" autocomplete="off">
@if(count($errors))
<div class="alert alert-danger">
<strong>Whoops!</strong> There is an error with your input.
<br/>
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="row">
<div class="col-md-6">
<div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
<input type="text" id="title" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}">
<span class="text-danger">{{ $errors->first('title') }}</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Create New Train</button>
</div>
</div>
</div>
</form>
<div class="panel panel-primary">
<div class="panel-heading">Train Management</div>
<div class="panel-body">
<form method="GET" action="{{ route('trains-lists') }}">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Search</button>
</div>
</div>
</div>
</form>
<table class="table">
<thead>
<th>Id</th>
<th>Train Title</th>
<th>Creation Date</th>
<th>Updated Date</th>
</thead>
<tbody>
@if($trains->count())
@foreach($trains as $key => $item)
<tr>
<td>{{ ++$key }}</td>
<td>{{ $item->title }}</td>
<td>{{ $item->created_at }}</td>
<td>{{ $item->updated_at }}</td>
</tr>
@endforeach
@else
<tr>
<td colspan="4">No train data available</td>
</tr>
@endif
</tbody>
</table>
{{ $trains->links() }}
</div>
</div>
</div>
</body>
</html>
The HTML code above contains a form element with an input field and a button for typing the title of a train before you save it to the database. The code also has an HTML table displaying the id, title, created_at, and updated_at details of a train entry within the database.
How To Use the Algolia Search
To view the page, navigate to http://127.0.0.1:8000/trains-lists from your web browser.
The database is currently empty, so you need to enter a title of a demo train in the input field and click Create New Train to save it.
To use the search feature, type a keyword from any saved train titles into the Enter Title For Search input field and click Search.
As shown in the image below, only search entries containing the keyword in their titles will display.
Meilisearch with Laravel Scout
Meilisearch is an open-source search engine focusing on speed, performance, and improved developer experience. It shares several features with Algolia, using the same algorithms, data structures, and research — but with a different programming language.
Developers can create and self-host a Meilisearch instance within their on-premises or cloud infrastructure. Meilisearch also has a beta cloud offering similar to Algolia for developers who want to use the product without managing its infrastructure.
In the tutorial, you already have a local instance of Meilisearch running within your Docker containers. You will now extend the Laravel Scout functionality to use the Meilisearch instance.
To add Meilisearch to the Laravel application, run the command below in your project terminal.
composer require meilisearch/meilisearch-php
Next, you need to modify the Meilisearch variables within the .env file to configure it.
Replace the SCOUT_DRIVER
, MEILISEARCH_HOST
, and MEILISEARCH_KEY
variables in the .env file with the ones below.
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=LockKey
The SCOUT_DRIVER
key specifies the driver that Scout should use, while MEILISEARCH_HOST
represents the domain where your Meilisearch instance is running. Although not required during development, adding the MEILISEARCH_KEY
in production is recommended.
Note: Comment out the Algolia ID and Secret when using Meilisearch as your preferred driver.
After completing the .env configurations, you should index your pre-existing records using the Artisan command below.
php artisan scout:import "App\Models\Train"
Laravel Scout with Database Engine
Scout’s database engine might be most suitable for applications that use smaller databases or manage less intensive workloads. Currently, the database engine supports PostgreSQL and MySQL.
This engine uses “where-like” clauses and full-text indexes against your existing database, enabling it to find the most relevant search results. You don’t need to index your records when using the database engine.
To use the database engine, you must set your SCOUT_DRIVER
.env variable to the database.
Open the .env file within the Laravel application and change the value of the SCOUT_DRIVER
variable.
SCOUT_DRIVER = database
After changing your driver to the database, Scout will switch to using the database engine for full-text search.
Collection Engine with Laravel Scout
In addition to the database engine, Scout also offers a collection engine. This engine uses “where” clauses and collection filtering to extract the most relevant search results.
Unlike the database engine, the collection engine supports all relational databases that Laravel also supports.
You can use the collection engine by setting the SCOUT_DRIVER
environment variable to collection
or by manually specifying the collection driver in the Scout configuration file.
SCOUT_DRIVER = collection
Explorer with Elasticsearch
With the strength of Elasticsearch queries, Explorer is a modern Elasticsearch driver for Laravel Scout. It offers a compatible Scout driver and benefits like storing, searching, and analyzing massive amounts of data in real time. Elasticsearch with Laravel offers results in milliseconds.
To use the Elasticsearch Explorer driver in your Laravel application, you’ll need to configure the boilerplate docker-compose.yml file that the Laravel-Scout script generated. You’ll add the additional configurations for Elasticsearch and restart the containers.
Open your docker-compose.yml file and replace its contents with the following.
# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.1/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
- redis
- meilisearch
- mailhog
- selenium
- pgsql
- elasticsearch
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: "%"
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
elasticsearch:
image: 'elasticsearch:7.13.4'
environment:
- discovery.type=single-node
ports:
- '9200:9200'
- '9300:9300'
volumes:
- 'sailelasticsearch:/usr/share/elasticsearch/data'
networks:
- sail
kibana:
image: 'kibana:7.13.4'
environment:
- elasticsearch.hosts=http://elasticsearch:9200
ports:
- '5601:5601'
networks:
- sail
depends_on:
- elasticsearch
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
pgsql:
image: 'postgres:13'
ports:
- '${FORWARD_DB_PORT:-5432}:5432'
environment:
PGPASSWORD: '${DB_PASSWORD:-secret}'
POSTGRES_DB: '${DB_DATABASE}'
POSTGRES_USER: '${DB_USERNAME}'
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
volumes:
- 'sailpgsql:/var/lib/postgresql/data'
networks:
- sail
healthcheck:
test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"]
retries: 3
timeout: 5s
meilisearch:
image: 'getmeili/meilisearch:latest'
ports:
- '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
volumes:
- 'sail-meilisearch:/meili_data'
networks:
- sail
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"]
retries: 3
timeout: 5s
mailhog:
image: 'mailhog/mailhog:latest'
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
selenium:
image: 'selenium/standalone-chrome'
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
- '/dev/shm:/dev/shm'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local
sail-meilisearch:
driver: local
sailpgsql:
driver: local
sailelasticsearch:
driver: local
Next, run the command below to pull the new Elasticsearch image you added to the docker-compose.yml file.
docker-compose up
Then, execute the Composer command below to install Explorer into the project.
composer require jeroen-g/explorer
You also need to create a configuration file for the Explorer driver.
Execute the Artisan command below to generate an explorer.config file for storing the configurations.
php artisan vendor:publish --tag=explorer.config
The configuration file generated above will be available in the /config directory.
In your config/explorer.php file, you can reference your model using the indexes
key.
'indexes' => [
\App\Models\Train::class
],
Change the value of the SCOUT_DRIVER
variable within the .env file to elastic
to configure Scout to use the Explorer driver.
SCOUT_DRIVER = elastic
At this point, you’ll use Explorer within the Train
model by implementing the Explorer interface and overriding the mappableAs()
method.
Open the Train.php file within the App > Models directory and replace the existing code with the code below.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use JeroenG\Explorer\Application\Explored;
use Laravel\Scout\Searchable;
class Train extends Model implements Explored
{
use HasFactory;
use Searchable;
protected $fillable = ['title'];
public function mappableAs(): array
{
return [
'id'=>$this->Id,
'title' => $this->title,
];
}
}
With the code you have added above, you can now use Explorer to search text within the Train
model.
For PHP developers, Laravel and add-ons like Scout make it a breeze to integrate fast, robust full-text search functionality. With the Database Engine, Collection Engine, and the capabilities of Meilisearch and Elasticsearch, you can interact with your app’s database and implement advanced search mechanisms in mere milliseconds.
Seamlessly managing and updating your database means your users receive an optimal experience while your code remains clean and efficient.
With our Application and Database Hosting solutions, Kinsta is your one-stop shop for all your modern Laravel development needs. The first $20 is on us.
Get all your applications, databases and WordPress sites online and under one roof. Our feature-packed, high-performance cloud platform includes:
- Easy setup and management in the MyKinsta dashboard
- 24/7 expert support
- The best Google Cloud Platform hardware and network, powered by Kubernetes for maximum scalability
- An enterprise-level Cloudflare integration for speed and security
- Global audience reach with up to 35 data centers and 275 PoPs worldwide
Get started with a free trial of our Application Hosting or Database Hosting. Explore our plans or talk to sales to find your best fit.