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

Elastica Bundle Laravel Package

fazland/elastica-bundle

Fazland Elastica Bundle integrates Elasticsearch into Symfony applications via the Elastica client. It offers configurable indexes and mappings, repository services, Doctrine entity persistence, and commands for managing and populating search indexes.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/elastica.php publishing step. Before you write a line of app code, decide which of three paths you are on:

  1. You are actually migrating away from it — read the config tree and mapping files, extract the index/type names and field definitions, and reimplement them against elasticsearch/elasticsearch or laravel-scout-elastic.
  2. You must run the last stable release (monorepo, inherited Symfony service, shared index contract) — install it and wire its services by hand.
  3. You are evaluating the new 5.0.0-alpha.3 — same wiring work as (2), plus acceptance that the API can change under you between alphas. Read the release notes as a roadmap of intent, not a stability guarantee.

First things to read, in this order:

  • src/DependencyInjection/Configuration.php — the entire configuration surface (clients, indexes, types, finder, serializer, plus the new onInvalidPath and _all defaults). This is the contract you have to translate.
  • src/DependencyInjection/FazlandElasticaExtension.php — shows how config becomes service definitions; this is what you replicate in a Laravel service provider.
  • src/Doctrine/ (listeners/subscribers) and src/Provider/ — the auto-indexing and population machinery.
  • src/Finder.php / src/Repository.php — the two classes your application code actually calls.

Minimal first use case: index one Eloquent model, populate it, and search it.

composer require fazland/elastica-bundle:5.0.0-alpha.3  # or pin the last stable

You'll need ruflin/elastica matching whatever Elasticsearch you're actually running — check the composer constraint carefully (see Gotchas).

// A hand-rolled Laravel provider replacing the Symfony DI extension
$this->app->singleton(Client::class, fn () => new Client([
    'host' => config('elastica.host'),
    'port' => config('elastica.port'),
]));

$this->app->singleton('elastica.index.products', fn ($app) =>
    $app->make(Client::class)->getIndex('products')
);

Then build an index, a type/mapping, and use the package's Finder against it. Your first real win is Finder::find() returning hydrated objects instead of raw arrays.

Implementation Patterns

Config shape translation. The bundle config is a nested clients → indexes → types → persistence tree. Map it to a Laravel config file and build the same objects yourself. Keep the same key names — it makes diffing against the Symfony app trivial and makes a future migration a rename, not a rewrite.

Population via a custom provider. The bundle's ProviderInterface is the cleanest seam. In Symfony it's fed by Doctrine; in Laravel implement it over an Eloquent cursor:

class ProductProvider implements ProviderInterface
{
    public function populate(Client $client, array $options = []): void
    {
        Product::query()->chunkById(500, function ($products) use ($client) {
            $docs = $products->map(fn ($p) => new Document($p->id, $p->toSearchableArray()));
            $client->getIndex('products')->addDocuments($docs);
        });
    }
}

Two search modes, pick deliberately. find() hydrates full entities (via a Transformation/callback you supply) — convenient but slow and N+1-prone. For listing pages, use the hybrid/_source path and hydrate only what you render. This is the single biggest day-to-day performance lever.

Auto-indexing. The bundle ships Doctrine event subscribers for save/delete. In Laravel you replace them with model observers. Copy the pattern, not the code:

Product::saved(fn ($p) => dispatch(new IndexProduct($p)));
Product::deleted(fn ($p) => dispatch(new DeleteProductFromIndex($p)));

Queue these. Synchronous indexing from an observer means a slow Elasticsearch node turns into slow HTTP requests.

Zero-downtime reindex via aliases. The bundle's index-name/alias handling exists because mapping changes require a full rebuild. Populate products_v2, then atomically repoint the products alias. If the fork's alias support is thin, implement it yourself with Indices::updateAliases() — it's ~10 lines and it's the difference between a deploy and an outage.

Repository subclassing. Extend the base Repository for domain-specific queries (searchAvailable(), searchByCategory()) so controllers never touch Elastica\Query directly. This is also your test seam — swap the repository in tests.

Date handling (new in 5.0.0-alpha.3). DateTimeInterface support means you no longer have to hand-format every timestamp before it hits a date field. Still be explicit in mappings: a date field with format: strict_date_optional_time and Carbon instances is the sane combination. Do not rely on the implicit path in production until you've diffed the generated document against what you previously sent.

Mappings: fail fast on bad paths. onInvalidPath is the new knob controlling what happens when a configured mapping path doesn't exist on the document. Set it to fail loudly in development so a renamed model attribute becomes a boot error rather than a silently missing field. Whatever the default is, do not inherit it accidentally in a Laravel config translation.

Split-indexing populate. The new no-index option on reset/populate is aimed at Symfony console commands, but the underlying idea ports over: build the index, load documents without touching live traffic, then swap the alias. In Laravel that's two queued jobs and an alias update — the flag just documents the intent.

Gotchas and Tips

The Symfony/Laravel impedance mismatch is the whole story. The bundle autoloads a Bundle class, an Extension, and a compiler pass — all of it requires a Symfony kernel. In Laravel you use none of that; you get the source classes and nothing else. The new no-index option lives on the bundle's Symfony commands, which you cannot use — it's a hint about intended workflow, not a feature you can call. Budget for writing the wiring yourself, and don't expect composer require to leave you with a working setup.

5.0.0-alpha.3 is a pre-release, explicitly not for production. The release notes say so verbatim, and they also say APIs are subject to change. That is a direct contradiction of the previous "last release was December 2017" picture, but it does not make the package safe: it makes it moving. Pin the exact alpha hash, read the diff between alphas before bumping, and treat the changelog as the only migration guide you'll get.

_all mapping settings are a version red flag. _all was deprecated in Elasticsearch 6.x and removed in 7.x. A release that adds _all defaults is telling you what generation of ES mapping API the maintainers are targeting. Verify the ruflin/elastica constraint and your cluster version before building on this, exactly as you would for the stable release. If you're on ES 7+, still assume this won't work.

It's a fork of FOSElasticaBundle with 16 stars. A burst of alpha activity after years of silence is not the same as maintenance. There is no stated support window, no published upgrade path, and the changelog for this release is five bullet points with no issue links. Any bug you hit, you fix.

Population memory blowups. The classic failure: the provider holds document references while iterating. Use chunk/cursor, drop references, and flush the index in batches. Watch for listeners firing on every hydrated model during populate and re-indexing recursively — disable observers for the duration of the populate command.

Missing documents are silent. Elasticsearch returns results for what it has, not for what it should have. After the first populate, compare Product::count() to the index's doc count. Do this every deploy. This is also how you catch a bad onInvalidPath setting dropping fields.

Debugging queries. Elastica exposes a logger (Elastica\Log) and the query object serializes to JSON via $query->toArray(). Log the compiled query body — 90% of "why doesn't this match" bugs are an analyzer or field-mapping mismatch, visible immediately in the JSON.

Mapping drift. dynamic: true mappings will happily invent field types from the first document they see (a numeric-looking SKU becomes a long, then breaks). Set dynamic: strict on types you care about during development. onInvalidPath covers configured paths; it does nothing for fields that appear by accident.

Extension points worth knowing: custom ProviderInterface (population), custom Transformation/callbacks (entity ↔ document), custom Repository (queries), and the serializer hook if you want to swap the bundle's JMS serializer for Laravel's JsonResource. Those four cover nearly every real customization need.

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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr