jackardios / elastic-query-wizard
Laravel Elastic Query Wizard
Installs: 437
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
pkg:composer/jackardios/elastic-query-wizard
Requires
- php: ^8.1
- jackardios/elastic-scout-driver-plus: ^v4.0.0
- jackardios/laravel-query-wizard: ^v2.0.2
- laravel/framework: ^v10.0
Requires (Dev)
- ext-json: *
- babenkoivan/elastic-migrations: ^v3.4.0
- jackardios/laravel-eloquent-spatial: ^2.0
- laravel/legacy-factories: ^1.0.4
- laravel/scout: ^v10.8.0
- orchestra/testbench: ^v8.21.1
- phpunit/phpunit: ^9.5
- roave/security-advisories: dev-latest
README
A powerful Laravel package for building Elasticsearch queries with JSON:API style filtering, sorting, and relation loading. Built on top of laravel-query-wizard and es-scout-driver.
Table of Contents
Features
- Declarative API — define allowed filters, sorts, and includes in one place
- Security — only explicitly allowed parameters are applied to queries
- Full-text Search — match, multi_match, fuzzy and other Elasticsearch query types
- Geo Queries — filter and sort by geographic coordinates
- Flexible Configuration — pass additional parameters to any query
- Eloquent Integration — load relations and accessors after Elasticsearch query execution
- JSON:API Compatible — standardized query parameter format
Requirements
- PHP 8.1+
- Laravel 10, 11, or 12
- Elasticsearch 8.x
- es-scout-driver
- laravel-query-wizard
Installation
composer require jackardios/elastic-query-wizard
Make sure your model uses the Searchable trait from es-scout-driver:
use Jackardios\EsScoutDriver\Searchable; class Post extends Model { use Searchable; // ... }
Quick Start
Basic Example
use Jackardios\ElasticQueryWizard\ElasticQueryWizard; use Jackardios\ElasticQueryWizard\ElasticFilter; use Jackardios\ElasticQueryWizard\ElasticSort; // GET /posts?filter[status]=published&filter[title]=laravel&sort=-created_at&include=author $posts = ElasticQueryWizard::for(Post::class) ->allowedFilters([ ElasticFilter::term('status'), ElasticFilter::match('title'), ElasticFilter::range('created_at'), ]) ->allowedSorts([ ElasticSort::field('created_at'), ElasticSort::field('title'), ]) ->allowedIncludes(['author', 'comments']) ->build() ->execute() ->models();
Geo Filtering Example
// GET /places?filter[nearby][lat]=55.75&filter[nearby][lon]=37.62&filter[nearby][distance]=10km $places = ElasticQueryWizard::for(Place::class) ->allowedFilters([ ElasticFilter::geoDistance('location', 'nearby'), ElasticFilter::term('category'), ]) ->allowedSorts([ ElasticSort::geoDistance('location', 55.75, 37.62, 'distance'), ]) ->build() ->execute() ->models();
Full-text Search Example
// GET /articles?filter[search]=elasticsearch tutorial&filter[category]=tech $articles = ElasticQueryWizard::for(Article::class) ->allowedFilters([ ElasticFilter::multiMatch(['title^2', 'body', 'tags'], 'search') ->withParameters([ 'type' => 'best_fields', 'fuzziness' => 'AUTO', ]), ElasticFilter::term('category'), ]) ->defaultSorts('-created_at') ->build() ->execute() ->models();
Documentation
Detailed documentation for each section:
| Section | Description |
|---|---|
| Filters | All filter types: term, match, range, geo, fuzzy, and more |
| Sorts | Sorting by fields, geography, and scripts |
| Includes | Loading Eloquent relations after Elasticsearch query |
| Advanced Usage | Custom filters, aggregations, working with SearchBuilder |
Usage Examples
Date Range Filtering
// GET /orders?filter[created_at][gte]=2024-01-01&filter[created_at][lte]=2024-12-31 ElasticQueryWizard::for(Order::class) ->allowedFilters([ ElasticFilter::range('created_at'), ElasticFilter::term('status'), ]) ->build() ->execute() ->models();
Autocomplete Search (Prefix)
// GET /users?filter[username]=joh ElasticQueryWizard::for(User::class) ->allowedFilters([ ElasticFilter::prefix('username'), ]) ->build() ->execute() ->models();
Typo-tolerant Search (Fuzzy)
// GET /products?filter[name]=iphon (will find "iphone") ElasticQueryWizard::for(Product::class) ->allowedFilters([ ElasticFilter::fuzzy('name')->withParameters([ 'fuzziness' => 'AUTO', ]), ]) ->build() ->execute() ->models();
Field Selection
// GET /posts?fields[posts]=id,title,status ElasticQueryWizard::for(Post::class) ->allowedFields(['id', 'title', 'status', 'body', 'created_at']) ->build() ->execute() ->models();
Using Aliases
Aliases allow you to use different parameter names in your API:
// GET /products?filter[tag]=electronics&sort=-date ElasticQueryWizard::for(Product::class) ->allowedFilters([ // Internal field: category, API parameter: tag ElasticFilter::term('category', 'tag'), ]) ->allowedSorts([ // Internal field: created_at, API parameter: date ElasticSort::field('created_at', 'date'), ]) ->build() ->execute() ->models();
Default Sorting
ElasticQueryWizard::for(Post::class) ->allowedSorts(['created_at', 'title', 'views']) ->defaultSorts('-created_at') // Default: newest first ->build() ->execute() ->models();
Working with Soft Deletes
// GET /posts?filter[trashed]=with (include trashed) // GET /posts?filter[trashed]=only (only trashed) ElasticQueryWizard::for(Post::class) ->allowedFilters([ ElasticFilter::trashed(), ]) ->build() ->execute() ->models();
Query Parameter Format
The package uses a standardized JSON:API style parameter format:
| Parameter | Format | Example |
|---|---|---|
| Filters | filter[field]=value |
?filter[status]=active |
| Sorting | sort=field or sort=-field |
?sort=-created_at |
| Includes | include=relation1,relation2 |
?include=author,comments |
| Fields | fields[resource]=field1,field2 |
?fields[posts]=id,title |
| Appends | append=accessor1,accessor2 |
?append=full_name |
Testing
composer test
License
MIT License. See LICENSE file for details.