Weave 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

kunstmaan/search-bundle

KunstmaanSearchBundle brings search functionality to Symfony applications, offering indexing, querying, and configurable integrations for Kunstmaan CMS content. It helps developers add flexible, maintainable site search and manage results through a structured bundle.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it is a Symfony bundle, not a Laravel package. kunstmaan/search-bundle was built for Symfony 2.x (KunstmaanSearchBundle extends Symfony\Component\HttpKernel\Bundle\Bundle) and its last release was April 2014. You cannot composer require it into a Laravel app — it will pull in symfony/framework-bundle 2.x, symfony/dependency-injection 2.x and an ancient Elastica, and none of the Symfony DI machinery (service tags, compiler passes, bundle bootstrapping) exists in Laravel's container.

So the day-to-day value for a Laravel developer is as a reference implementation of a provider abstraction over Elasticsearch, not as a dependency.

Where to look, in order:

  1. SearchConfigurationInterface — the whole bundle is built around this contract.
  2. The DI extension / compiler pass that collects services tagged as search configurations.
  3. The Elastica provider service — the thin search() wrapper around Elastica queries.
  4. The console command(s) that build/populate indexes.

The first use case the bundle was designed for: you have a Doctrine entity you want searchable. You write a service implementing SearchConfigurationInterface that declares the index name, the document type, the fields to index and how to populate them; you tag that service; the bundle aggregates all tagged configurations into one provider and exposes search across them.

In Laravel, the equivalent first use case is Scout:

composer require laravel/scout
composer require matchish/laravel-scout-elasticsearch   # or babenkoivan/elastic-scout-driver
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
// config/scout.php
'driver' => env('SCOUT_DRIVER', 'elasticsearch'),
class Product extends Model
{
    use Searchable;

    public function toSearchableArray(): array
    {
        return ['id' => $this->id, 'name' => $this->name, 'description' => $this->description];
    }
}

That gets you the same shape of thing this bundle offered in 2014, on a stack that still runs.

Implementation Patterns

The bundle's model is worth copying even if the code isn't.

One configuration object per indexable domain type. Each implementation answers: what index, what type, what fields, what's the document id, and how do I populate it. The bundle then registers the provider as a single service and you call search() against it.

The provider is a thin wrapper, not a query builder. Queries are Elastica Query objects — you write the Elasticsearch DSL yourself. There is no fluent abstraction hiding the ES API. Expect to hand-write bool/multi_match/filtered bodies.

In Laravel the mirror is:

interface SearchConfiguration
{
    public function index(): string;
    public function type(): string;
    public function documentId($model): string;
    public function toDocument($model): array;
    public function modelClass(): string;
}

class SearchRegistry
{
    /** @var SearchConfiguration[] */
    public function __construct(private array $configurations) {}

    public function for(string $modelClass): SearchConfiguration { /* ... */ }
}

Bind it in a service provider from a config array or by scanning a directory — Laravel's answer to "tagged services" is explicit registration in a ServiceProvider::register().

Index lifecycle as commands/jobs, not request-time work.

  • php artisan search:reindex {model} → delete index, create with mapping, bulk-index in chunks.
  • On model save/delete, dispatch a queued job (IndexModel / RemoveFromIndex) rather than hitting Elasticsearch synchronously. The bundle's populateIndex() was typically run from a console command precisely because it's slow.
  • Prefix index names by environment (products_staging, products_production) so a local reindex never touches production.

Bulk is the only sane populate path. If you copy one thing from the bundle's provider, copy its use of Elastica's bulk API: ~500–1000 documents per request, refresh: false during the load, a single refresh at the end.

Gotchas and Tips

  • It's abandoned and version-locked. No Symfony 3/4 support, no Elasticsearch 5/6/7+. The getIndexType() method is a direct artifact of ES 1.x mapping types, which were removed in ES 7 and are gone entirely in 8. Don't try to retrofit it; the concepts survive, the code doesn't.
  • Dependency conflicts are guaranteed. Even in a Symfony 2 project of that era, mixing it with anything modern is painful. Keep it out of any Laravel composer.json.
  • Tagged-service name must match exactly. In the Symfony original, a typo in the service tag silently excludes your configuration from the provider — no error, just missing results. If you reimplement the pattern in Laravel, prefer an explicit registry array over magic string keys so a missing entry is a startup error, not a silent miss.
  • Mapping changes require an index rebuild. Changing the fields returned by your configuration does not update the mapping. Delete the index, recreate it, reindex. Same trap applies in Scout — php artisan scout:flush then scout:import.
  • Debug with Elasticsearch directly, not through the bundle. curl localhost:9200/_cat/indices?v, curl localhost:9200/products/_mapping?pretty, and check the document count matches your table before blaming the query. Elastica's exceptions are thin wrappers around ES error bodies; log the full response.
  • Extension point worth keeping: a SearchProviderInterface with a search(string $query, array $options): Result method, so you can swap Elastica for the official elasticsearch/elasticsearch client (8.x) later without touching controllers. The bundle did this; do it too.
  • Watch relevance, not just results. The old bundle gave you fields but no analyzer configuration — the default standard analyzer will disappoint on names, SKUs and partial matches. Define text fields with analyzer/search_analyzer and keyword sub-fields in your mapping from day one; retrofitting analyzers means another full reindex.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource