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.
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:
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.
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.
~x.y in Composer and treat upgrades as "fork or migrate" events, not routine.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.search:reconcile early and schedule it.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.How can I help you explore Laravel packages today?