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

Search Bundle Laravel Package

bkstg/search-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require bkstg/search-bundle
    

    Add to config/app.php under providers:

    Backstage\SearchBundle\SearchServiceProvider::class,
    

    Publish the config file:

    php artisan vendor:publish --provider="Backstage\SearchBundle\SearchServiceProvider" --tag=config
    
  2. Basic Configuration Edit config/search.php to define your search engines (e.g., Algolia, Elasticsearch, or custom adapters). Example:

    'engines' => [
        'default' => [
            'driver' => 'algolia',
            'api_key' => env('ALGOLIA_API_KEY'),
            'app_id' => env('ALGOLIA_APP_ID'),
            'index_name' => 'products',
        ],
    ],
    
  3. First Search Query Inject the Search facade or service into a controller:

    use Backstage\SearchBundle\Facades\Search;
    
    public function search(Request $request)
    {
        $results = Search::query($request->input('q'))
            ->engine('default')
            ->get();
    
        return view('results', compact('results'));
    }
    
  4. Model Integration Add a Searchable trait to your Eloquent model:

    use Backstage\SearchBundle\Traits\Searchable;
    
    class Product extends Model
    {
        use Searchable;
    }
    

    Define searchable fields in config/search.php under models.Product.


Implementation Patterns

Query Building

  • Chaining Methods Leverage fluent methods for complex queries:

    $results = Search::query('laptop')
        ->engine('default')
        ->filter('price', '<', 1000)
        ->sort('created_at', 'desc')
        ->limit(10)
        ->get();
    
  • Dynamic Filtering Use request input for dynamic filters:

    $filters = $request->only(['category', 'min_price', 'max_price']);
    $results = Search::query($request->q)
        ->engine('default')
        ->filters($filters)
        ->get();
    
  • Pagination Integrate with Laravel's pagination:

    $results = Search::query($request->q)
        ->engine('default')
        ->paginate(15);
    

Model Synchronization

  • Auto-Sync on Save Enable automatic sync to search engine via config/search.php:

    'sync' => [
        'enabled' => true,
        'events' => ['creating', 'updating', 'deleting'],
    ],
    

    Manually trigger sync for a model:

    $product->syncToSearch();
    
  • Bulk Sync Sync multiple models at once:

    Search::sync([$product1, $product2, $product3]);
    

Custom Adapters

  • Extend for New Engines Create a custom adapter by implementing Backstage\SearchBundle\Contracts\SearchEngine:
    class CustomEngine implements SearchEngine
    {
        public function search(string $query, array $filters = []): array
        {
            // Custom logic
        }
    
        public function sync(array $models): void
        {
            // Custom sync logic
        }
    }
    
    Register in config/search.php:
    'engines' => [
        'custom' => [
            'driver' => 'custom',
            'class' => \App\Search\CustomEngine::class,
        ],
    ],
    

Facade vs. Service Container

  • Facade for Simplicity Use Search::query() in controllers/views for brevity.
  • Service Binding for Complex Logic Bind the service in AppServiceProvider for dependency injection:
    $this->app->bind('search', function ($app) {
        return new \Backstage\SearchBundle\SearchService($app['config']['search']);
    });
    

Gotchas and Tips

Debugging

  • Query Logging Enable debug mode in config/search.php:

    'debug' => env('APP_DEBUG', false),
    

    Logs will appear in storage/logs/laravel.log.

  • Adapter-Specific Errors Handle engine-specific exceptions:

    try {
        $results = Search::query($q)->engine('algolia')->get();
    } catch (\Backstage\SearchBundle\Exceptions\AlgoliaException $e) {
        Log::error('Algolia error: ' . $e->getMessage());
        return back()->withError('Search service unavailable');
    }
    

Configuration Quirks

  • Environment Variables Ensure .env variables are loaded (e.g., ALGOLIA_API_KEY). Use php artisan config:clear if changes aren’t reflected.

  • Index Name Conflicts Avoid duplicate index names across engines. Prefix with engine name if needed:

    'index_name' => 'algolia_products',
    
  • Field Mapping Explicitly define searchable fields in config/search.php to avoid runtime errors:

    'models' => [
        \App\Models\Product::class => [
            'fields' => ['name', 'description', 'sku'],
            'custom_mapping' => [
                'price' => 'numeric',
                'tags' => 'tags',
            ],
        ],
    ],
    

Performance Tips

  • Batch Sync For large datasets, use chunking:

    Product::chunk(100, function ($products) {
        Search::sync($products);
    });
    
  • Cache Results Cache frequent queries:

    $results = Cache::remember("search_{$request->q}", now()->addHours(1), function () use ($request) {
        return Search::query($request->q)->engine('default')->get();
    });
    

Extension Points

  • Event Listeners Listen for sync events to add pre/post-processing:

    Search::listen(function ($model) {
        // Modify model before sync
        $model->searchableData['boost'] = 2;
    });
    
  • Custom Highlighting Extend the SearchResult class to add custom highlighting:

    class CustomSearchResult extends \Backstage\SearchBundle\SearchResult
    {
        public function highlight(string $field): string
        {
            // Custom logic
        }
    }
    

    Bind in AppServiceProvider:

    $this->app->bind(\Backstage\SearchBundle\SearchResult::class, \App\Search\CustomSearchResult::class);
    

Common Pitfalls

  • Missing Sync Events Ensure sync events are enabled in config/search.php to avoid stale data.

  • Case Sensitivity Algolia/Elasticsearch may treat queries case-sensitively by default. Configure in engine settings:

    'options' => [
        'ignore_case' => true,
    ],
    
  • Rate Limiting Respect API rate limits (e.g., Algolia’s 1000 requests/minute). Implement retries:

    use Backstage\SearchBundle\Exceptions\RateLimitExceeded;
    
    try {
        $results = Search::query($q)->engine('algolia')->get();
    } catch (RateLimitExceeded $e) {
        sleep(60); // Wait and retry
        $results = Search::query($q)->engine('algolia')->get();
    }
    
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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware