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

Elasticsearch Search String Parser Laravel Package

spatie/elasticsearch-search-string-parser

Parse custom search strings into Elasticsearch queries. Supports regex-based directives like status:active or @user, grouping directives, and autocomplete suggestions. Build searches via spatie/elasticsearch-query-builder and get results + directive suggestions.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/elasticsearch-search-string-parser
    

    Requires spatie/elasticsearch-query-builder (install via composer require spatie/elasticsearch-query-builder).

  2. Basic Usage: Define a parser class extending Spatie\SearchStringParser\SearchStringParser:

    use Spatie\SearchStringParser\SearchStringParser;
    
    class CustomSearchParser extends SearchStringParser
    {
        public function __construct()
        {
            $this->addDirective('status', 'active|inactive');
            $this->addDirective('group_by', 'project|user');
        }
    }
    
  3. First Use Case: Parse a search string into an Elasticsearch query:

    $parser = new CustomSearchParser();
    $query = $parser->parse('foo bar status:active group_by:project');
    
    // Outputs a query builder instance (compatible with spatie/elasticsearch-query-builder)
    

Where to Look First


Implementation Patterns

Core Workflow

  1. Define Directives: Register custom directives (e.g., filters, groupings) with regex patterns:

    $parser->addDirective('priority', '/high|medium|low/');
    $parser->addDirective('date_range', '/(\d{4}-\d{2}-\d{2})\s*to\s*(\d{4}-\d{2}-\d{2})/');
    
  2. Parse and Build Queries:

    $parser = new CustomSearchParser();
    $query = $parser->parse('priority:high date_range:2023-01-01 to 2023-12-31');
    
    // Convert to Elasticsearch DSL
    $elasticsearchQuery = $query->toElasticsearchQuery();
    
  3. Integration with Laravel: Bind the parser to the container in AppServiceProvider:

    $this->app->singleton(CustomSearchParser::class, function () {
        return new CustomSearchParser();
    });
    

    Use in controllers/routes:

    $query = app(CustomSearchParser::class)->parse(request('q'));
    

Advanced Patterns

  • Dynamic Directives: Load directives from a config file or database:

    $directives = config('search.directives');
    foreach ($directives as $name => $pattern) {
        $parser->addDirective($name, $pattern);
    }
    
  • Grouping and Nesting: Use groupBy() for hierarchical queries:

    $parser->addDirective('group_by', 'project|user');
    $query = $parser->parse('group_by:project')->groupBy('project');
    
  • Auto-Completion: Implement Spatie\SearchStringParser\AutoCompleteProvider for suggestions:

    class ProjectAutoCompleteProvider implements AutoCompleteProvider
    {
        public function getSuggestions(string $query): array
        {
            return Project::where('name', 'like', "%{$query}%")->limit(5)->pluck('name')->toArray();
        }
    }
    
  • Combining with Query Builder: Extend Spatie\QueryBuilder\QueryBuilder to support parsed queries:

    $queryBuilder = new QueryBuilder();
    $queryBuilder->addQuery($parser->parse('status:active')->toElasticsearchQuery());
    

Gotchas and Tips

Common Pitfalls

  1. Regex Overlap:

    • Directives with overlapping patterns (e.g., status:active vs. active) may cause parsing ambiguity.
    • Fix: Order directives from most specific to least specific or use anchors (^/$).
  2. Case Sensitivity:

    • Regex patterns are case-sensitive by default. Use i modifier for case-insensitive matches:
      $parser->addDirective('status', '/active|inactive/i');
      
  3. Whitespace Handling:

    • Directives like group_by:project may fail if the input has inconsistent spacing (e.g., group_by : project).
    • Fix: Trim input or use flexible regex:
      $parser->addDirective('group_by', '/group_by\s*:\s*(project|user)/i');
      
  4. Query Builder Incompatibility:

    • The parsed query must align with spatie/elasticsearch-query-builder's expected structure.
    • Debug: Use dd($query->toElasticsearchQuery()) to inspect the generated DSL.

Debugging Tips

  • Log Parsed Tokens: Enable debug mode to see tokenized input:

    $parser->enableDebug();
    $tokens = $parser->tokenize('status:active'); // Inspect tokens
    
  • Validate Directives: Use getDirectives() to list registered directives:

    dd($parser->getDirectives());
    
  • Test Edge Cases: Test with:

    • Empty strings.
    • Malformed directives (e.g., status: without a value).
    • Unicode characters or special symbols.

Extension Points

  1. Custom Tokenizers: Override tokenize() to handle non-standard formats (e.g., JSON-encoded queries).

  2. Post-Processing: Use afterParsing() callback to modify the query:

    $parser->afterParsing(function ($query) {
        $query->addMustNot(['term' => ['deleted' => true]]);
    });
    
  3. Dynamic Directive Loading: Implement Spatie\SearchStringParser\DirectiveLoader to fetch directives from an API or cache.

  4. Performance:

    • Cache parsed queries if the same search string is reused.
    • Pre-compile regex patterns for directives.

Configuration Quirks

  • Default Directives: The package includes basic directives (e.g., not:, must:). Override them carefully:

    $parser->addDirective('not', '/not\s*(.+)/i'); // Customize negation logic
    
  • Grouping Syntax: Ensure group_by: directives are registered before parsing to avoid conflicts with other directives.

  • Elasticsearch Version: The generated DSL may need adjustments for Elasticsearch <7.0 (e.g., filter vs. bool queries). Use toElasticsearchQuery() with version-specific options.

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