Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Explorer Laravel Package

jeroen-g/explorer

Laravel-friendly wrapper for Explorer, a lightweight full-text search engine. Index and search your Eloquent models with simple configuration, fast queries, and flexible ranking/filters. Ideal for adding on-site search without running Elasticsearch or Algolia.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require jeroen-g/explorer
    php artisan vendor:publish --tag=explorer.config
    

    Update config/explorer.php with your Elasticsearch connection details.

  2. Model Integration: Add Searchable trait and implement Explored interface (or use config-based mapping):

    use Laravel\Scout\Searchable;
    use JeroenG\Explorer\Application\Explored;
    
    class Post extends Model implements Explored {
        use Searchable;
    
        public function mappableAs(): array {
            return ['title' => 'text', 'published' => 'boolean'];
        }
    }
    
  3. First Search:

    $results = Post::search('query')->get();
    

Key First Use Cases

  • Basic Search: Use search() with a query string.
  • Pagination: Chain take(20) or use Laravel's paginate().
  • Sorting: Use orderBy('field', 'direction') (e.g., orderBy('published_at', 'desc')).

Implementation Patterns

Core Workflows

  1. Indexing:

    // Auto-index on save (Scout default)
    Post::create(['title' => 'Test']);
    
    // Manual update
    Post::all()->each->updateSearchData();
    
  2. Query Composition:

    $results = Post::search('query')
        ->must(new Matching('title', 'query'))
        ->filter(new Term('published', true))
        ->get();
    
  3. Aggregations:

    $results = Post::search()
        ->aggregation('categories', new TermsAggregation('category'))
        ->raw();
    

Integration Tips

  • Hybrid Search: Combine with Laravel Scout's toSearchableArray() for dynamic fields.
  • Nested Data: Use Nested queries and dot notation for nested fields (e.g., author.name).
  • Custom Queries: Extend SyntaxInterface for Elasticsearch-specific queries (e.g., GeoDistance).

Example: Advanced Search Controller

public function search(Request $request) {
    $query = Post::search($request->q)
        ->filter(new Term('status', 'published'))
        ->orderBy('created_at', 'desc')
        ->take(50);

    if ($request->has('category')) {
        $query->must(new Matching('category', $request->category));
    }

    return $query->get();
}

Gotchas and Tips

Pitfalls

  1. Mapping Conflicts:

    • Elasticsearch infers types if not explicitly defined. Use mappableAs() or config to avoid runtime errors.
    • Fix: Publish config and define all critical fields (e.g., id as keyword).
  2. Nested Queries:

    • Dot notation (e.g., author.name) requires proper nested mapping in mappableAs().
    • Fix: Ensure nested objects are defined as nested in the mapping.
  3. Pagination Limits:

    • Elasticsearch defaults to size: 10. Use take() to increase limits (e.g., take(100)).
    • Warning: Large take() values may impact performance.
  4. Alias Mismatches:

    • Aliases (read, write) require Aliased interface or config enablement.
    • Fix: Implement Aliased or add model to indexes in config.

Debugging

  • Raw Queries: Use ->raw() to inspect Elasticsearch payloads.
  • Fake Responses: Test without Elasticsearch using FakeResponse (see testing.md).
    $this->instance(ElasticClientFactory::class, ElasticClientFactory::fake($fakeResponse));
    

Performance Tips

  • Field Selection: Use ->field('title', 'id') to reduce payload size (though Elasticsearch still processes full docs).
  • Query Caching: Cache frequent aggregations or complex queries.
  • Index Aliases: Enable prune_old_aliases to avoid bloated history indices.

Extension Points

  1. Custom Syntax:

    // Example: Add a `Range` query
    class Range implements SyntaxInterface {
        public function build(): array {
            return ['range' => ['price' => ['gte' => 100]]];
        }
    }
    
  2. Query Properties:

    // Example: Add `timeout` to queries
    class Timeout implements QueryProperty {
        public function __construct(private int $ms) {}
        public function build(): array { return ['timeout' => $this->ms]; }
    }
    
  3. Testing:

    • Use FakeResponse for unit tests (mock Elasticsearch responses).
    • Example: Store test responses in tests/Support/Elastic/Responses/.

Config Quirks

  • Index Names: Must be unique. Override searchableAs() if needed.
  • Dynamic Mapping: Avoid mixing mappableAs() and config-based mapping for the same model.
  • Boolean Fields: Ensure published/active flags are mapped as boolean to avoid scoring issues.

Common Errors & Fixes

Error Cause Solution
MappingException Missing/invalid field mapping Define all fields in mappableAs() or config.
No hits Query syntax mismatch Use ->raw() to debug the query payload.
AliasNotFoundException Alias not configured Implement Aliased or update config.
Slow queries Unoptimized aggregations Limit aggregation fields or use size: 0.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport