novaway/elasticsearch-bundle
Symfony bundle that integrates Elasticsearch into your application, providing configuration, service definitions, index management, and a web profiler panel to inspect queries. Simplifies wiring Elasticsearch clients and building search features.
This is a Symfony bundle (novaway/elasticsearch-bundle) that wraps the official elasticsearch/elasticsearch PHP client with configuration, a Finder helper, and a thin client wrapper. There is no Laravel service provider — treat it as a source of reusable classes plus a reference config schema, not a drop-in Laravel package.
Minimum steps:
composer require novaway/elasticsearch-bundle — 2.7.1 relaxes the Symfony constraint to include Symfony 7, which matters on Laravel 11/12 (both ship Symfony 7 components). If you hit a constraint conflict, you are likely on an older Laravel.bootstrap/providers.php or config/app.php. Symfony bundle autodiscovery doesn't exist in Laravel.DependencyInjection/Configuration.php — the full set of options (hosts, index, type, logging, finder defaults).Resources/config/services.yml — shows exactly which services the bundle wires and how, so you can reproduce it in a service provider.Finder class — the only part with real day-to-day value; it builds Elasticsearch query arrays from a small fluent API.Elasticsearch\Client in AppServiceProvider (copy the ClientBuilder setup from the bundle's service definition), then either use the bundle's Finder standalone (new Finder($client)) or go straight to $client->search([...]).If all you need is querying, skipping the bundle and installing elasticsearch/elasticsearch directly is a legitimate choice — you lose the Finder convenience, not much else.
Manual container wiring. The bundle's value is its service definitions. Reproduce them:
// AppServiceProvider::register()
$this->app->singleton(Client::class, function () {
return ClientBuilder::create()
->setHosts(config('elasticsearch.hosts'))
->setLogger(app(LoggerInterface::class)) // wire Monolog
->build();
});
$this->app->bind(Finder::class, fn ($app) => new Finder($app->make(Client::class)));
Port the config schema. Mirror Configuration.php into config/elasticsearch.php (hosts, index, type, logging, finder defaults). Keep index names environment-scoped (env('ELASTICSEARCH_INDEX', 'app_'.app()->environment())) rather than hardcoding.
Finder as the daily driver. Wrap it behind your own repository/search service so the Symfony-flavoured API doesn't leak into controllers:
final class ProductSearch
{
public function __construct(private Finder $finder) {}
public function search(string $term): array
{
return $this->finder
->find(config('elasticsearch.index'), 'product')
->setQuery(['bool' => ['must' => [['match' => ['name' => $term]]]]])
->getResult();
}
}
Index lifecycle via Artisan. Index/type management belongs in commands, not in the bundle config:
php artisan es:index:create — create index with explicit mappings.php artisan es:index:reindex — alias swap (products_v2 → alias products) for zero-downtime mapping changes.php artisan es:index:delete --force.Write path. Index documents from a queued job/observer rather than synchronously in the request cycle; Elasticsearch refresh latency and partial failures will otherwise surface as flaky user-facing behaviour.
Testing. Swap the client binding in tests for a stub implementing the handful of elasticsearch-php methods you call (or mock Client), and assert against the query array the Finder produces. Since you control the Finder binding, this is trivial — a real argument for the manual-wiring approach.
composer require fails on Laravel 11+, confirm you're resolving 2.7.1 and not a stale lockfile.novaway_elasticsearch.* container params) does not happen in Laravel. If you follow a Symfony tutorial verbatim you'll get Target [Finder] is not instantiable errors.elasticsearch/elasticsearch 7.x and 8.x have incompatible APIs (typed type removal, different query defaults). Check which client version your composer resolution actually picked; the bundle's type-oriented config is 7.x-shaped and needs adjusting for 8.x.index/type semantics. The bundle's config predates Elasticsearch 8's type removal. If you're on ES 8, treat type as vestigial and pass _index carefully; don't assume the bundle's defaults match your cluster.logging and hand a Monolog channel to ClientBuilder::setLogger() — the raw query dump is the fastest way to debug a "no results" report. Elasticsearch's own error bodies are verbose but precise; log them, don't swallow them.Finder to add domain methods, or decorate your own binding. The bundle's client wrapper is thin enough that most teams eventually replace it — do that deliberately rather than layering on top of both.How can I help you explore Laravel packages today?