Treat this as an internal/experimental package, not a batteries-included integration: 3 stars, 0 dependents, last tagged release 2022-03-17. Before you plan around it, budget an hour to read the source — you will be the one maintaining it.
composer require pion/laravel-lelastico then pin the exact constraint in composer.json (e.g. "pion/laravel-lelastico": "0.x.*"). With no downstream users, minor bumps carry no de-facto compatibility guarantee.composer.json for extra.laravel.providers for auto-discovery. If it isn't there, add the provider from src/ to config/app.php manually — verify the namespace class-by-class from the source rather than trusting blog snippets.php artisan vendor:publish --provider="Pion\LaravelLelastico\LelasticoServiceProvider". If no tag is documented, publish by provider. The resulting config/lelastico.php (or similarly named file) is the package's real API surface — read it end to end before writing any application code..env. Bring up a local Elasticsearch in Docker so you can inspect http://localhost:9200/_cat/indices?v and confirm what the package actually creates.php artisan list | grep -i lelastico for any indexing/reindex commands, then read the provider's register() and boot() to see what is bound in the container and which classes are singletons.First use case: index a single existing Eloquent model and search it end to end — no bulk, no observers. That exercise tells you three things you need immediately: what document structure the package produces, how it names indices (prefix/suffix behaviour), and whether it returns arrays, Eloquent models, or its own result objects. Everything after that is repetition.
Illustrative shape — confirm the real facade/manager names against src/ before copying:
// index
app('lelastico')->index('products')->add($product->toArray());
// search
$results = app('lelastico')->index('products')->search('wireless keyboard');
Put a seam between your app and the package. Wrap every call behind your own SearchService interface bound in a service provider. Given the package's maintenance profile, you want the ability to swap to elasticsearch/elasticsearch or babenkoivan/elastic-scout-driver by rewriting one class, not by grepping 40 call sites.
interface ProductSearch
{
public function index(Product $product): void;
public function remove(Product $product): void;
public function query(array $filters, int $page = 1): array;
}
Index from model events, not controllers. A created/updated/deleted observer (or a single saved/deleted pair) keeps the index convergent regardless of which code path wrote the row — seeders, Nova, tinker, queue workers. Dispatch the actual indexing to a queued job so a slow cluster doesn't add latency to web requests.
Own the mapping. Do not let dynamic mapping guess your field types in production; dates and numeric strings will be inferred wrong and you will discover it via silently broken range filters. Keep mappings in version-controlled JSON and apply them explicitly before the first index.
Use aliases for zero-downtime reindexing. Write to products_v3, then atomically repoint the products alias. Build this yourself — a package at this maturity level will not do it for you, and adding fields later will otherwise mean downtime.
Batch your writes. Single-document indexing is fine for the first test; backfills need bulk requests in chunks of ~500–1000 documents with a fresh index refresh budget. Anything that loops one row at a time over 50k products will take hours.
Isolate search in tests. Bind a fake implementation of your interface in the test container, and keep one small integration test suite that runs against a real container. Do not mock the package's internals — you'll couple tests to code you don't control.
repositories entry rather than waiting upstream.elasticsearch/elasticsearch transitively. If your cluster is ES 8 and the package drags in a 7.x client, you'll get opaque handshake or content-type errors at runtime, not at install time. Check composer why elasticsearch/elasticsearch early.config:cache masks config edits. Every time you change the config file during setup, php artisan config:clear. This burns people for an hour at a time.POST /products/_search?pretty. Nine times out of ten the bug is a mapping mismatch, not your filters.refresh. Searches immediately after a write will miss the document until the index refreshes (~1s default). Set refresh=true on writes only in tests and dev; never in production.chunkById rather than chunk on large tables.README note in the fork and pin by commit SHA. Six months from now nobody will remember why the vendor directory is special.How can I help you explore Laravel packages today?