Utilisation de Laravel Scout pour implémenter la recherche textuelle

Le framework Laravel s’est affirmé comme une ressource indispensable pour les développeurs qui œuvrent dans la création de services web.

En tant qu’outil open source, Laravel propose une multitude de fonctionnalités prêtes à l’emploi, facilitant ainsi la création d’applications robustes et fonctionnelles.

Parmi ces fonctionnalités, on trouve Laravel Scout, une bibliothèque dédiée à la gestion des index de recherche au sein d’une application. Sa flexibilité permet aux développeurs de personnaliser les configurations et de choisir parmi différents pilotes tels qu’Algolia, Meilisearch, MySQL ou Postgres pour le stockage des index.

Dans ce contexte, nous allons approfondir notre compréhension de cet outil en vous guidant à travers le processus d’ajout de la prise en charge de la recherche textuelle à une application Laravel en utilisant le pilote. Vous allez modéliser une application Laravel à des fins de démonstration, enregistrant les noms de trains fictifs, puis utiliser Laravel Scout pour intégrer une fonction de recherche à l’application.

Prérequis

Avant de suivre ce tutoriel, assurez-vous de disposer des éléments suivants :

  • Un compilateur PHP installé sur votre ordinateur. Ce tutoriel utilise la version 8.1 de PHP.
  • Le moteur Docker ou Docker Desktop installé sur votre ordinateur.
  • Un compte cloud Algolia, que vous pouvez créer gratuitement.

Installation de Scout dans un projet Laravel

Pour utiliser Scout, vous devez tout d’abord créer une application Laravel à laquelle vous souhaitez ajouter la fonctionnalité de recherche. Le script Bash Laravel-Scout contient les commandes nécessaires pour générer une application Laravel dans un conteneur Docker. L’utilisation de Docker élimine la nécessité d’installer des logiciels supplémentaires tels qu’une base de données MySQL.

Étant écrit en Bash, le script Laravel-Scout nécessite un environnement Linux pour son exécution. Si vous utilisez Windows, assurez-vous d’avoir configuré Windows Subsystem for Linux (WSL).

Si vous utilisez WSL, exécutez la commande suivante dans votre terminal pour définir votre distribution Linux préférée.

wsl -s ubuntu

Ensuite, naviguez jusqu’à l’emplacement de votre choix sur votre ordinateur pour placer le projet. Le script Laravel-Scout créera un répertoire de projet à cet emplacement. Dans l’exemple ci-dessous, le script crée un répertoire sur le bureau.

cd /desktop

Exécutez la commande suivante pour lancer le script Laravel-Scout, qui configurera une application Dockerisée avec le code de base requis.

curl -s https://laravel.build/laravel-scout-app | bash

Après l’exécution, changez de répertoire en utilisant la commande `cd laravel-scout-app`. Ensuite, exécutez `sail-up` dans le dossier du projet pour démarrer les conteneurs Docker de votre application.

Note : Sur de nombreuses distributions Linux, il se peut que vous deviez exécuter la commande avec `sudo` pour obtenir des privilèges élevés.

./vendor/bin/sail up

Vous pourriez rencontrer une erreur.

Error stating the port is allocated Error stating the port is allocated.

Pour la résoudre, utilisez la variable `APP_PORT` pour spécifier un port dans la commande `sail up`.

APP_PORT=3001 ./vendor/bin/sail up

Enfin, lancez l’application via Artisan sur le serveur PHP en exécutant la commande suivante.

php artisan serve

Accédez à l’application depuis votre navigateur web en visitant l’adresse http://127.0.0.1:8000. Vous devriez voir la page de bienvenue de Laravel à la route par défaut.

Ajout de Laravel Scout à l’application

  1. Dans votre terminal, utilisez la commande suivante pour activer le gestionnaire de paquets Composer PHP et ajouter Laravel Scout au projet :
composer require laravel/scout
  1. Ensuite, publiez le fichier de configuration Scout en utilisant la commande `vendor:publish`. Cette commande va placer le fichier de configuration `scout.php` dans le répertoire `config` de votre application :
 php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
  1. Maintenant, modifiez le fichier `.env` du modèle standard pour inclure une valeur booléenne à la variable `SCOUT_QUEUE`. Cette valeur permet à Scout de mettre les opérations en file d’attente, améliorant ainsi les temps de réponse. Sans cette valeur, les pilotes Scout tels que Meilisearch ne refléteront pas immédiatement les nouveaux enregistrements.
    SCOUT_QUEUE=true
  1. Modifiez également la variable `DB_HOST` dans le fichier `.env` pour qu’elle pointe vers votre localhost, ce qui permettra d’utiliser la base de données MySQL dans les conteneurs Docker.
DB_HOST=127.0.0.1

Avec ces étapes, vous avez ajouté Laravel Scout à votre application, publié le fichier de configuration nécessaire, et configuré les variables d’environnement pour optimiser le fonctionnement de Scout avec une file d’attente et une base de données MySQL dans les conteneurs Docker.

Marquer un modèle et configurer l’index avec Laravel Scout

Création d’un modèle

Pour l’application Train, où vous souhaitez stocker les noms provisoires de chaque train disponible, commencez par générer une migration en utilisant la commande Artisan suivante, en la nommant `create_trains_table` :

php artisan make:migration create_trains_table 

Ouvrez le fichier de migration généré situé dans le répertoire `database/migrations/` et ajoutez le code suivant après la colonne `id()` à la ligne 17 pour créer une colonne de titre :

$table->string('title');

Appliquez ensuite la migration avec la commande suivante :

php artisan migrate

Après l’exécution des migrations de base de données, créez un fichier nommé `Train.php` dans le répertoire `app/Models/`.

Ajout du Trait `Laravel\Scout\Searchable`

Marquez le modèle `Train` comme consultable en ajoutant le trait `Laravel\Scout\Searchable` au modèle. Ouvrez le fichier `Train.php` et ajoutez le trait comme suit :

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Train extends Model
{
    use Searchable;
    public $fillable = ['title'];

Configurez les index de recherche en surchargeant la méthode `searchableAs`. Par défaut, Scout persisterait le modèle pour correspondre au nom de la table du modèle. Ajoutez le code suivant au fichier `Train.php` :

/**
     * Retrieve the index name for the model.
     *
     * @return string
    */
    public function searchableAs()
    {
        return 'trains_index';
   }
}

Avec ces étapes, vous avez marqué le modèle `Train` comme consultable avec Laravel Scout, en lui ajoutant le trait approprié et en configurant les index de recherche pour utiliser le nom personnalisé `trains_index`.

Utilisation d’Algolia avec Laravel Scout

Pour la première recherche en texte intégral avec Laravel Scout, vous allez utiliser le pilote Algolia.

Configuration d’Algolia

Commencez par installer le package client Algolia pour PHP dans votre application en exécutant la commande suivante :

composer require algolia/algoliasearch-client-php

Dans votre fichier `.env`, définissez votre ID d’application et votre clé API secrète Algolia. Pour obtenir ces informations, suivez ces étapes :

  1. Accédez à votre tableau de bord Algolia via votre navigateur web.
  2. Cliquez sur « Settings » en bas de la colonne latérale de gauche pour accéder à la page des paramètres.
  3. Ensuite, cliquez sur « API Keys » dans la section « Team and Access » pour afficher les clés de votre compte Algolia. Notez les valeurs « Application ID » et « Admin API Key ».

Ajoutez les informations d’identification à votre fichier `.env` en utilisant votre éditeur de code.

Remplacez les espaces réservés par les secrets API Algolia correspondants. Assurez-vous également de changer la variable `SCOUT_DRIVER` comme suit pour utiliser le pilote Algolia :

ALGOLIA_APP_ID=APPLICATION_ID
ALGOLIA_SECRET=ADMIN_API_KEY

Avec ces étapes, vous avez installé le package client Algolia pour PHP dans votre application Laravel et configuré les informations d’identification nécessaires dans le fichier `.env` pour permettre à Laravel Scout d’utiliser le pilote Algolia.

SCOUT_DRIVER=algolia

Création des contrôleurs d’application

  1. Dans le répertoire `app/Http/Controllers/`, créez un fichier `TrainSearchController.php` pour stocker un contrôleur dédié à l’application. Ce contrôleur sera responsable de la gestion des opérations liées au modèle Train, notamment l’affichage et l’ajout de données.
  2. Ajoutez le bloc de code suivant dans le fichier `TrainSearchController.php` pour construire le contrôleur :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Train;

class TrainSearchController extends Controller
{
    /**
     * Compile the content for a trains list view.
     *
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
    */
    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'));
    }

    /**
     * Create a new train entry.
     *
     * @return \Illuminate\Http\RedirectResponse
    */
    public function create(Request $request)
    {
        $this->validate($request,['title'=>'required']);

        $trains = Train::create($request->all());
        return back();
    }

Création des routes de l’application

Ouvrez votre fichier `routes/web.php` et remplacez le code existant par le bloc ci-dessous :

<?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');

Ce code définit deux routes dans l’application. La requête GET pour l’itinéraire `/trains-lists` répertorie toutes les données de train stockées, tandis que la requête POST pour l’itinéraire `/create-item` crée de nouvelles données sur les trains.

Avec ces étapes, vous avez créé un contrôleur `TrainSearchController` pour gérer les opérations du modèle Train, et vous avez configuré les routes nécessaires dans le fichier `web.php`.

Création des vues de l’application

  1. Créez un fichier dans le répertoire `resources/views/` et nommez-le `train-search.blade.php`. Ce fichier sera responsable de l’affichage de l’interface utilisateur pour la fonctionnalité de recherche.
  2. Ajoutez le contenu du bloc de code ci-dessous dans le fichier `train-search.blade.php` pour créer une page unique pour la fonctionnalité de recherche :
<!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>

Ce code HTML contient un élément de formulaire avec un champ de saisie et un bouton pour entrer le titre d’un train avant de l’enregistrer dans la base de données. Il inclut également un tableau HTML affichant les colonnes id, title, created_at et updated_at d’une entrée de train dans la base de données.

Avec ces étapes, vous avez créé la vue `train-search.blade.php` pour l’interface utilisateur de votre fonctionnalité de recherche.

Utilisation de la recherche Algolia

  1. Pour afficher la page, naviguez vers http://127.0.0.1:8000/trains-lists à partir de votre navigateur web.
  2. Comme la base de données est actuellement vide, vous devez saisir le titre d’un train de démonstration dans le champ de saisie et cliquer sur « Créer un nouveau train » pour l’enregistrer.
  3. Pour utiliser la fonction de recherche, saisissez un mot-clé parmi les titres de train enregistrés dans le champ de saisie « Saisir le titre pour la recherche » et cliquez sur « Rechercher ».
  4. Comme le montre l’image ci-dessous, seules les entrées de recherche contenant le mot-clé dans leur titre s’afficheront.

Note: Assurez-vous que votre application Laravel est en cours d’exécution et que les conteneurs Docker sont actifs pour permettre l’interaction avec la base de données et Algolia.

Utilisation de Meilisearch avec Laravel Scout

  1. Pour ajouter Meilisearch à l’application Laravel, exécutez la commande suivante dans le terminal de votre projet :
    composer require meilisearch/meilisearch-php
  1. Modifiez les variables de Meilisearch dans le fichier `.env` pour le configurer. Remplacez les variables `SCOUT_DRIVER`, `MEILISEARCH_HOST`, et `MEILISEARCH_KEY` dans le fichier `.env` par les valeurs ci-dessous. Assurez-vous de mettre en commentaire l’ID et le secret Algolia si vous utilisez Meilisearch comme pilote préféré :
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=LockKey

La clé `SCOUT_DRIVER` spécifie le pilote que Scout doit utiliser, `MEILISEARCH_HOST` représente le domaine où votre instance de Meilisearch s’exécute, et `MEILISEARCH_KEY` est la clé d’API Meilisearch. Bien que ce ne soit pas nécessaire pendant le développement, il est recommandé d’ajouter `MEILISEARCH_KEY` en production.

  1. Après avoir terminé les configurations dans le fichier `.env`, vous devez indexer vos enregistrements préexistants à l’aide de la commande Artisan suivante :
php artisan scout:import "App\Models\Train"

Utilisation de Laravel Scout avec le moteur de base de données

  1. Le moteur de base de données de Scout est plus adapté aux applications avec des bases de données plus petites ou des charges de travail moins intensives. Actuellement, le moteur de base de données supporte PostgreSQL et MySQL.
  2. Ce moteur utilise des clauses de type « where-like » et des index plein texte sur votre base de données existante, ce qui lui permet de trouver les résultats de recherche les plus pertinents. Vous n’avez pas besoin d’indexer vos enregistrements lorsque vous utilisez le moteur de base de données.
  3. Pour utiliser le moteur de base de données, vous devez définir la variable `SCOUT_DRIVER` dans le fichier `.env` sur la base de données. Ouvrez le fichier `.env` dans l’application Laravel et modifiez la valeur de la variable `SCOUT_DRIVER` :
SCOUT_DRIVER = database

Après avoir changé votre pilote pour la base de données, Scout utilisera le moteur de base de données pour la recherche en texte intégral.

Utilisation du moteur de collecte avec Laravel Scout

En plus du moteur de base de données, Scout propose également un moteur de collecte. Ce moteur utilise les clauses « where » et le filtrage des collections pour extraire les résultats de recherche les plus pertinents.

Contrairement au moteur de base de données, le moteur de collecte prend en charge toutes les bases de données relationnelles que Laravel prend également en charge.

Vous pouvez utiliser le moteur de collecte en définissant la variable d’environnement `SCOUT_DRIVER` sur `collection` dans le fichier `.env` de votre application Laravel, ou en spécifiant manuellement le pilote de collecte dans le fichier de configuration de Scout.

Pour utiliser le moteur de collecte, ouvrez le fichier `.env` et modifiez la valeur de la variable `SCOUT_DRIVER` comme suit :

SCOUT_DRIVER = collection

Exploration avec Elasticsearch à l’aide du pilote Explorer

Configurez le fichier `docker-compose.yml` en ajoutant les configurations nécessaires pour Elasticsearch. Ouvrez le fichier `docker-compose.yml` et remplacez son contenu par celui fourni.

`

# 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 

Exécutez la commande suivante pour extraire la nouvelle image Elasticsearch ajoutée au fichier `docker-compose.yml` :

docker-compose up

Ensuite, installez le pilote Explorer dans votre projet en exécutant la commande Composer suivante :

composer require jeroen-g/explorer

Créez un fichier de configuration pour le pilote Explorer.

Ensuite, générez un fichier `explorer.config` pour stocker les configurations avec la commande Artisan suivante :

php artisan vendor:publish --tag=explorer.config

Le fichier de configuration généré sera disponible dans le répertoire `/config`.

Dans le fichier `config/explorer.php`, référencez votre modèle en utilisant la clé `indexes`.

'indexes' => [
        \App\Models\Train::class
],

Changez la valeur de la variable `SCOUT_DRIVER` dans le fichier `.env` en `elastic` pour configurer Scout afin qu’il utilise le pilote Explorer :

SCOUT_DRIVER = elastic

Implémentez le pilote Explorer dans le modèle `Train` en ajoutant l’interface Explorer et en surchargeant la méthode `mappableAs()`. Ouvrez le fichier `Train.php` dans le répertoire `App\Models` et remplacez le code existant par celui fourni.

<?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,
        ];
    }
} 

Avec ces étapes, vous pouvez maintenant utiliser Explorer pour effectuer des recherches en texte intégral dans le modèle `Train` en utilisant Elasticsearch comme backend.

Conclusion

Pour les développeurs PHP, l’utilisation de Laravel avec des modules tels que Scout facilite l’intégration d’une fonctionnalité de recherche textuelle rapide et robuste. Les options de moteur de base de données, de moteur de collection, ainsi que les capacités de Meilisearch et Elasticsearch offrent des moyens flexibles d’interagir avec la base de données de manière efficace. Ces outils permettent la mise en œuvre de mécanismes de recherche avancés en quelques millisecondes.

L’utilisation transparente de la gestion et de la mise à jour de la base de données garantit une expérience optimale pour les utilisateurs, tout en maintenant un code propre et efficace.

Recommended For You

About the Author: Alex Bruno

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *