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

sylius/search-bundle

Sylius SearchBundle adds Elasticsearch-powered search to Sylius storefronts, enabling fast product indexing, configurable search indexes, and filtered catalog results for scalable e-commerce search.

View on GitHub
Deep Wiki
Context7

Getting Started

First, calibrate expectations. sylius/search-bundle is a Symfony bundle built for Sylius, not a Laravel package. There is no service provider, no facade, no Eloquent integration, and it depends on the deprecated ongr/elasticsearch-bundle. You will not composer require this into a Laravel app. Your realistic day-to-day leverage is one of two paths:

  1. You work inside a Sylius/Symfony storefront — then it's a real (if frozen) dependency and this guide applies directly.
  2. You're mining it as a reference — then read Document/, Indexer/, and Query/ to copy the design (event-driven indexing, document mappings, filter composition) into Laravel with Scout + Meilisearch/Typesense or the official elasticsearch/elasticsearch client.

Where to look first (in this order):

  • DependencyInjection/Configuration.php — the actual config surface: engine host, index name, document class mappings, indexable models.
  • Document/ — the indexed representations (Product, Taxon, variants, attributes). This is the schema; everything else serves it.
  • Indexer/ — how Doctrine entities become Elasticsearch documents, plus the console command (typically sylius:search:index) that does the full rebuild.
  • Finder/ + Query/Filter/ — how search queries and aggregations are composed from the request.
  • Resources/config/services.xml — wiring, so you know what's injectable and under what service ID.

Minimal first use case (Sylius context):

composer require sylius/search-bundle   # pin the exact version; no patches coming

Register Sylius\Bundle\SearchBundle\SyliusSearchBundle in config/bundles.php, configure sylius_search: (client host, index name, indexable classes), then:

bin/console sylius:search:index   # populate the index

Then inject the Finder service into a controller and run a query with a filter set. On a Laravel side, the equivalent first move is a spike on your chosen engine (Meilisearch index + Scout searchable()), not an install attempt.

Implementation Patterns

Event-driven sync (the core pattern to steal). The bundle subscribes to Sylius resource events (sylius.product.post_create, .post_update, .post_delete) and reindexes the affected document. For a Laravel port:

// AppServiceProvider — mirrors Sylius' resource-event indexing
Product::observe(new ProductSearchObserver());  // created/updated/deleted → dispatch(IndexProduct::class)

Always queue the indexing job, never index inline. In Sylius the subscribers can run synchronously; under a bulk import that degrades badly. In Laravel, IndexProduct should implement ShouldQueue and be batched for imports:

Bus::batch($products->map(fn ($p) => new IndexProduct($p)))->dispatch();

Document mapping is a product-domain decision. What you map into the index determines what facets and sorts you can offer. Port the Document/Product fields you actually need (name, slug, price, taxon, variant availability, attributes) — but also do the corresponding Laravel Scout toSearchableArray() equivalent:

public function toSearchableArray(): array
{
    return [
        'id'        => $this->id,
        'name'      => $this->translate()?->name,
        'slug'      => $this->slug,
        'price'     => (int) $this->price,
        'taxons'    => $this->taxons->pluck('code')->all(),
        'in_stock'  => $this->variants->contains(fn ($v) => $v->onHand > 0),
        'attributes'=> $this->attributes->pluck('value', 'code')->all(), // only filterable ones
        'locale'    => app()->getLocale(),
    ];
}

One index per locale/channel. Sylius models this to keep relevance language-specific; in Laravel use searchableAs() with locale suffix and query the right index at request time.

Keep engine access behind an interface. Finder in Sylius is the seam — reproduce it:

interface ProductSearchInterface {
    public function search(ProductQuery $q): ProductResultSet;
}

Swapping Meilisearch → Typesense → Elasticsearch later becomes a container binding change, not a rewrite.

Reindex tooling is a first-class citizen. Build a full-rebuild command and a reconciliation command from day one. The package gives you this on the Sylius side; Laravel doesn't hand it to you:

php artisan search:reindex --fresh     # flush + repopulate
php artisan search:reconcile          # diff DB → index, repair drift

Search endpoint layer. Keep controllers thin: a form request → a query DTO → the search service → a response resource. This is the bundle's Finder + Query composition shape, and it survives translation to Laravel without ceremony.

Gotchas and Tips

  • Archived means frozen. No CVEs will be patched, no PHP 8.x+ bumps, no Symfony major compat. Pin to ~x.y in Composer and treat upgrades as "fork or migrate" events, not routine.
  • Subtree split trap. This repo is a read-only split of the Sylius/Sylius monorepo. A patch means forking the monorepo and maintaining a divergent branch — far heavier than it looks. The 5 stars / 0 dependents are a metric artifact, not adoption data; check the parent project for real usage.
  • Do not try to install it in Laravel. It will drag in Sylius resource contracts, Doctrine, and Symfony bundle machinery. Dependency-resolution conflicts are the most likely first failure and the most expensive to unwind — they block unrelated upgrades.
  • Synchronous indexing under bulk operations is the #1 runtime pitfall if you copy subscriber patterns without queueing. Import 50k products and watch the request timeout — batch and queue from the start.
  • Index drift is silent. Search results diverge from the database; without a reconciliation job nobody notices until conversion drops. Build search:reconcile early and schedule it.
  • Locale/channel indices are easy to get wrong. Missing index → empty results, not an error. Log missing-index lookups as warnings.
  • Attribute mapping = feature surface. You can only facet/sort on mapped fields. Decide "filterable / sortable / merchandisable" per attribute before indexing; retro-fitting means reindexing everything.
  • Don't rely on the search bundle for engine ops. Cluster sizing, shard strategy, snapshot/restore, and version upgrades are yours — the bundle only gives you the PHP-side plumbing.
  • Extension points are the design blueprint. Indexer, Finder, filter classes, and document classes are the seams you'd replicate. Study them; don't copy them literally into Laravel — the primitives (Doctrine events, Symfony compiler passes) don't exist there.
  • Forking burden is real. A Sylius-monorepo fork for one bundle means tracking Symfony and Elasticsearch majors forever with no upstream. Budget a migration quarter, not a weekend, and only if you already depend on it.
  • Design-extraction is the actual deliverable. If you take nothing else from this package, take: event-triggered indexing on create/update/delete, document-per-locale, filter-composed query builders, and a full-reindex + reconcile pair. Those four patterns are the reusable asset; the code is not.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core