omure/scout-advanced-meilisearch
Installation
composer require omure/scout-advanced-meilisearch
Configure Scout
Update config/scout.php:
'driver' => env('SCOUT_DRIVER', 'meilisearch_advanced'),
'meilisearch_advanced' => [
'host' => env('MEILISEARCH_HOST', 'http://127.0.0.1:7700'),
'index_name' => env('MEILISEARCH_INDEX', 'laravel'),
'api_key' => env('MEILISEARCH_MASTER_KEY', null),
],
First Use Case Define a searchable model:
use Omure\ScoutAdvancedMeilisearch\Searchable;
class Product extends Model
{
use Searchable;
public function toSearchableArray()
{
return [
'name' => $this->name,
'price' => $this->price,
'tags' => $this->tags,
'created_at' => $this->created_at,
];
}
}
Run indexing:
php artisan scout:import "App\Models\Product"
Basic Filtering
// Range queries
$products = Product::search('laptop')->where('price', '>=', 500)->get();
// Between ranges
$products = Product::search('phone')->whereBetween('price', [300, 800])->get();
// Complex conditions
$products = Product::search('electronics')
->where(function ($query) {
$query->where('price', '<=', 1000)
->orWhere('tags', 'contains', 'sale');
})
->get();
Array Field Searching
// Search within nested arrays
$products = Product::search('wireless')
->where('tags', 'contains', 'bluetooth')
->get();
// Exact array matching
$products = Product::search('accessories')
->where('tags', '=', ['usb', 'cable'])
->get();
Dynamic Filtering
// Build filters from request
$filters = request()->query('filters', []);
$query = Product::search(request('q'));
foreach ($filters as $field => $value) {
if (str_contains($value, ',')) {
$query->whereIn($field, explode(',', $value));
} else {
$query->where($field, $value);
}
}
Pagination with Filters
$results = Product::search('gadget')
->where('price', '<=', 300)
->paginate(10);
Hybrid Search
// Combine full-text and attribute filters
$results = Product::search('wireless headphones')
->where('brand', 'Sony')
->orderBy('price', 'asc')
->get();
searchable:saved/searchable:deleted for custom logic.scout:searching for query logging/analytics.Index Schema Mismatch
toSearchableArray() returns fields matching your Meilisearch index schema.php artisan scout:flush and re-import after schema changes.Filterable Attributes
where() clauses.curl -X POST "http://localhost:7700/indexes/laravel/settings" \
-H "Content-Type: application/json" \
-d '{"filterableAttributes": ["price", "brand", "tags"]}'
Array Field Queries
contains only works on indexed array fields (not raw database arrays).tags is indexed as an array in Meilisearch.Total Count Accuracy
->get() with large datasets; use ->count() or ->paginate() instead.Query Inspection
$query = Product::search('test')->where('price', '>', 100);
dd($query->toMeilisearchQuery()); // Raw Meilisearch query
Index Health Check Meilisearch logs or use:
curl http://localhost:7700/health
Performance
->limit(100) during development to avoid overloading Meilisearch.curl http://localhost:7700/indexes/laravel/stats
Custom Drivers
Extend Omure\ScoutAdvancedMeilisearch\Drivers\MeilisearchAdvancedDriver for protocol-specific logic.
Query Macros Add reusable query methods:
Scout::extend(function ($scout) {
$scout->macro('inStock', function ($query) {
return $query->where('stock', '>', 0);
});
});
Collection Driver for Tests
Use collection_advanced in phpunit.xml:
<env name="SCOUT_DRIVER" value="collection_advanced"/>
laravel by default).Product::chunk(100, function ($products) {
$products->searchable();
});
How can I help you explore Laravel packages today?