Skip to content

Recherche

La recherche produit s'appuie sur Laravel Scout + Meilisearch. Seul Product est indexé, et tout passe par une façade — le contrat ProductIndexService (indexation, recherche, facettes).

Ce qui est indexé

Product::toSearchableArray() agrège le produit parent et ses variantes en ligne en un seul document : noms par locale, références, catégories, valeurs d'attributs et prix HT. Le rôle de chaque champ côté Meilisearch est déclaré au SearchIndexRegistry — par le cœur (CoreSearchIndex) comme par les packages :

UsageAttributs
Recherche plein texte (searchableAttributes)names, references
Filtres & facettes (filterableAttributes)categories, attribute_values, prices (+ id, names, references)
Tri (sortableAttributes)names, order_in_categories, prices, created_at

Ces réglages sont posés au démarrage dans config('scout.meilisearch.index-settings') — le fichier de config est chargé avant les providers, il ne peut donc pas lire un registre encore vide — puis poussés à Meilisearch par scout:sync-index-settings. Pour ajouter un champ à l'index, déclarez un attribut au registre (voir registres) : toSearchableArray() y fusionne les attributs contribués. Le remplacement complet du document reste possible en surchargeant la méthode sur votre modèle — voir modèles.

Indexation découplée (hors requête)

Le modèle désactive l'auto-sync de Scout : la requête HTTP n'attend jamais Meilisearch. À la place, les observers du domaine (Product, Price, Category, CategoryProduct) émettent l'événement ReindexRequested avec les IDs concernés ; un listener queueable réindexe en arrière-plan via ProductIndexService::index().

php
use Slab\Framework\Core\Search\Events\ReindexRequested;

// Réindexer après votre propre logique métier :
ReindexRequested::dispatch([$product->id]);

Un dispatch([]) (liste vide) ne réindexe rien — il ne déclenche pas de réindexation globale.

Facettes & filtres

Les facettes sont réelles : prix (intervalle min/max), valeurs d'attributs (multi-sélection) et catégorie. Pour chaque catégorie, l'éventail de filtres applicables est pré-calculé à partir des produits en ligne et stocké en base (colonne filters JSON, via CategoryService) ; le composant front le relit pour afficher le slider de prix et les cases d'attributs. Ce que la catégorie propose est déclaré au CatalogFilterRegistry : le calcul d'un côté, la vue qui le rend de l'autre — un package ajoute donc un filtre sans toucher ni au service de catégorie ni au thème.

À la recherche, ces choix sont traduits en syntaxe de filtre Meilisearch (categories IN [...], prices >= …) par les traductions déclarées au SearchIndexRegistry, et getFacetedSearch() renvoie les produits et la distribution de facettes (facetDistribution).

TIP

Synonymes, stop words et ranking rules ne sont pas paramétrés : Slab s'en tient aux défauts de Meilisearch. Réglez-les sur l'index si votre catalogue le demande.

Par où l'étendre

Je veux…Point d'extensionMécanique
indexer un champ, l'exposer en facette, le filtrer ou le trierSearchIndexRegistryregistres
ajouter un filtre à la page de catégorieCatalogFilterRegistryregistres
remplacer entièrement le document indexétoSearchableArray (modèle Searchable)modèles
réindexer après un changement métierReindexRequestedévénements
remplacer le moteur ou la stratégie de rechercheProductIndexService (bind)conteneur

Exemple : remplacer le service de recherche

Le cœur lie le contrat à son implémentation par défaut ; rebindez-le pour brancher votre moteur :

php
use Slab\Framework\Core\Product\Contracts\ProductIndexService;

// index(): (ré)indexe · search(): construit la requête Scout · getFacetedSearch(): résultats + facettes
$this->app->bind(ProductIndexService::class, MonMoteurDeRecherche::class);

Commandes utiles

CommandeRôle
scout:import "Slab\Framework\Models\Product"(ré)indexe tout le catalogue
scout:sync-index-settingsapplique searchable/filterable/sortable à l'index
meilisearch:reinit --reindexrecrée l'index vide, réapplique les réglages, réindexe
meilisearch:documents {productId?}inspecte les documents réellement indexés

Voir aussi