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

Flexmodel Elasticsearch Bundle Laravel Package

flexmodel/flexmodel-elasticsearch-bundle

A Laravel/PHP bundle that connects FlexModel to Elasticsearch, enabling model indexing, full-text search, filtering, and query building so you can add fast, scalable search to your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first, updated for 0.1.0. The only thing the new release tells us is that this is now an initial release — 0.1.0, notes: “Initial release.” There is no changelog history, no migration guide, no upgrade path, and no prior users to learn from. Treat everything below as pre-1.0 and therefore unstable in the literal sense: any patch release can rename a service, change a config key, or alter how a model becomes a mapping. Pin the exact version in composer.json ("flexmodel/flexmodel-elasticsearch-bundle": "0.1.0") rather than using a caret range, and read composer.json and Tests/ yourself before committing to anything.

What the package still is, structurally: a thin Symfony DI bundle wrapping the FlexModel concept (plain PHP model classes mapped onto a storage backend) plus an Elasticsearch storage adapter. Two consequences for a Laravel developer:

  1. There is no service provider, no facade, no config/ file. It’s Symfony bundle plumbing — a Bundle class, DependencyInjection/*Extension.php, Resources/config/services.yml. In Laravel you will register the services by hand, not “install and go.”
  2. The dependency graph is dated. Expect an elasticsearch/elasticsearch client of the 2.x/5.x era and PHP constraints that may fight a modern Laravel app. The 0.1.0 release being brand new does not mean the internals are modern — verify the constraints.

Where to look first, in this order:

  • composer.json — the exact elasticsearch/elasticsearch and symfony/* constraints. This decides whether you can use it at all.
  • DependencyInjection/ and Resources/config/ — the bundle exposes almost nothing else. Whatever services exist (client, index manager, storage) are declared here; that is the public API surface at 0.1.0.
  • The FlexModel storage adapter package it depends on. Real behaviour — model → index/type/mapping, query translation — lives there, not in the bundle.
  • Tests/ — with a package this small and this young, tests are the only reliable documentation of the mapping and query contract. At 0.1.0 they are also your only signal of what the author actually intended.

Minimal wiring (Symfony shape, translate by hand for Laravel):

// Bundles registration, Symfony 3/4 era shape
$bundles = [
    new FlexModel\ElasticSearchBundle\FlexModelElasticSearchBundle(),
];

// config.yml
flex_model_elastic_search:
    clients:
        default:
            hosts: ['http://localhost:9200']
    # index/type/model mapping usually happens through FlexModel "presets"

First use case worth proving end-to-end: one model, one index, one document indexed, one search returned. Define a model class with properties, register it under a FlexModel preset pointed at the default client, index a document, run a term query through the model’s repository/storage. If that round-trip works against your ES version, everything else is variations. If it fails in the first hour, stop — the failure mode is usually an incompatible ES server version or an assumption the 0.1.0 tests never covered, and neither is fixed by config.

For Laravel, do not try to run the bundle. Harvest the idea and the mapping logic, and bind a client yourself:

// app/Providers/ElasticServiceProvider.php
$this->app->singleton(\Elasticsearch\Client::class, fn () => \Elasticsearch\ClientBuilder::create()
    ->setHosts(config('elasticsearch.hosts'))
    ->build());

Implementation Patterns

Model-as-document. The FlexModel premise is that your PHP model is storage-agnostic and you attach a storage (here, Elasticsearch) to it. In practice the model carries field definitions and the adapter derives index mappings from them. Keep models small and flat. Nested objects and arrays are where these adapters are weakest, and mapping drift between PHP field types and the ES mapping is the number one source of silent data loss — you index a document, _source looks right, but the field isn’t searchable because it mapped as text vs keyword, or the document was rejected and you never inspected the response.

// Illustrative shape, not verbatim API — verify against the storage package
class Product extends \FlexModel\Model
{
    protected $id;
    protected $name;
    protected $price;
    protected $tags = [];
}

One model per index/type, one preset per environment. Treat the FlexModel “preset” as your environment boundary (dev, staging, production) mapping to a client plus index name. This is what makes the package tolerable: application code asks for a preset by name, and index naming/prefixing lives in config, not code. At 0.1.0 expect this config shape to be the thing most likely to change between patch releases — isolate it in one file.

Push the query DSL through rather than fighting the abstraction. The adapter will cover CRUD and simple criteria; anything beyond degrades into array-shaped ES queries anyway. Own the query body in a thin repository and keep the adapter out of your domain:

class ProductSearchRepository
{
    public function __construct(private \Elasticsearch\Client $client) {}

    public function search(string $term): array
    {
        $res = $this->client->search([
            'index' => 'products',
            'body'  => [
                'query' => [
                    'multi_match' => ['query' => $term, 'fields' => ['name^2', 'tags']],
                ],
            ],
        ]);

        return array_column($res['hits']['hits'], '_source');
    }
}

The integration tip that matters most: let the package own indexing, never let it own querying. Indexing is mechanical and the model → mapping translation is the only genuinely useful thing here. Search is where the abstraction leaks and where you need raw DSL for relevance tuning, aggregations, and pagination.

Bulk indexing. Single-document indexing through an ORM-style adapter will time out on any real backfill. Batch writes and flush explicitly — with this era of client that means building the bulk body yourself and using the model-to-array conversion only as each action’s _source.

Keep it behind an interface. Whatever you do with this package, wrap it:

interface ProductIndexer {
    public function index(Product $product): void;
    public function delete(int $id): void;
}

interface ProductSearcher {
    public function search(ProductQuery $query): ProductResultSet;
}

At 0.1.0 with no adoption history, the only defensible adoption is one where swap-out cost is a single binding. Write the direct-client implementation first, keep the FlexModel-based one as an A/B alternative, and you get the model-mapping idea without the dependency becoming load-bearing.

Index lifecycle is your job, not the bundle’s. There is no alias/rollover management here. Create indices explicitly, use aliases so you can reindex into a new one and flip, and always refresh in tests or you will chase phantom failures.

Gotchas and Tips

  • 0.1.0 means the API is not settled. “Initial release” is the entire changelog — there is no evidence of what the author considers stable. Pin the exact version, wrap everything behind your own interfaces, and expect that upgrading a minor will require reading source diffs. Do not build the package directly into domain code.
  • Version lock is the whole story. The bundle pins an old elasticsearch/elasticsearch. ES 6 removed multiple mapping types; ES 7 removed them entirely and changed the client API significantly. On a 7.x/8.x cluster the adapter’s type-based document paths (/index/type/id) will 400 or 404 immediately. Check the server version against the client constraint before anything else.
  • Young, not necessarily abandoned — but unsupervised. A fresh 0.1.0 with a single release and no dependents means no security patches you didn’t write, no PHP 8 or Laravel 11 compatibility work, and no bug responses until the author ships again. Fork or extract the mapping logic and budget for that explicitly rather than discovering it in six months.
  • Silent write failures. Old ES clients return error responses without throwing, especially on bulk. Always inspect $response['errors'] and per-item status. A document indexed “successfully” that never appears in search is almost always a mapping rejection or a refresh-timing issue.
  • Mapping drift. ES infers mappings from the first document. First doc has price as integer, next a decimal → rejected. First doc has tags: [] → mapped as text with no keyword subfield → you can’t aggregate and won’t notice until a dashboard is wrong. Define mappings explicitly and disable dynamic mapping for fields you care about.
  • Refresh semantics. refresh: true on writes is a test/dev convenience; in production it turns bulk loads into index thrashing. Set refresh_interval: -1 during backfills, then restore and force-merge.
  • Config is split across two packages. Failures often look like bundle misconfiguration when they’re actually a FlexModel preset misconfiguration (or vice versa). When a service is missing from the container, dump it (debug:container in Symfony, or bind and dd() in Laravel) and find which package was meant to register it.
  • Debugging queries. Don’t trust the abstraction to log what it sent. Point the client at a proxy (mitmproxy, or an ES slow-log at level: trace) for one reproduction run. Half of “the package is broken” is a query the adapter built differently than you assumed.
  • Extension points are narrow but real. The bundle’s value is DI wiring and the client service, and both are overridable. A custom storage/model mapping class is the intended seam. Anything needing new query capability is not an extension point — drop to the raw client.
  • The honest recommendation. For a Laravel codebase, use elasticsearch/elasticsearch directly (or laravel/scout with a first-party ES driver) behind a small mapping layer you own. The FlexModel idea — storage-agnostic models — is appealing, but at 0.1.0 with a single release and no adoption this is a reference implementation, not a runtime dependency. Read it for how to structure model → index mapping; don’t make it load-bearing.
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.
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator
manelgavalda/enrollment_mobile
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics