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

Sphinxsearch Bundle Laravel Package

rosh1ck/sphinxsearch-bundle

Sphinxsearch Bundle integrates Sphinx full-text search into PHP applications, offering configuration and services to index and query data. Use it to connect your app to Sphinx and add fast, scalable search.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: this is a Symfony bundle — Symfony2, with release 0.2.5 merely adding Symfony3 support. It ships a SphinxsearchBundle class extending Symfony\Component\HttpKernel\Bundle\Bundle, a DI extension, and a service definition for the Sphinx client — none of which Laravel will autoload or register. Symfony 2 went EOL in 2018 and Symfony 3 in 2021; the bundle has had no meaningful feature work since ~2020. So "getting started" for a Laravel developer is really: extract the query-side wrapper, skip the bundle.

Step 1 — Install what you'll actually use. Add the underlying Sphinx PHP client rather than the bundle:

composer require sphinxsearch/sphinxsearch

Then read DependencyInjection/Configuration.php and Resources/config/services.xml from the bundle repo on GitHub to see the config keys (host, port, indexes) and how the client is constructed. That's the only part you'll port.

Step 2 — Stand up Sphinx/Manticore separately. The bundle does not run the search daemon; it only talks to it. Install searchd (or better, Manticore Search, the maintained fork), write sphinx.conf with a source pointing at your Laravel DB, and run indexer --all once to prove data flows.

Step 3 — First use case: search a products table. Register a singleton in AppServiceProvider:

$this->app->singleton(SphinxClient::class, function () {
    $c = new SphinxClient();
    $c->setServer(config('sphinx.host', '127.0.0.1'), config('sphinx.port', 9312));
    $c->setMatchMode(SPH_MATCH_EXTENDED2);
    return $c;
});

Then $client->query('iphone', 'products_index') and inspect $result['matches'] (doc IDs + weights). Look first at the bundle's Sphinxsearch.php/service class — it's ~100 lines wrapping exactly this.

Implementation Patterns

Two-connection model. Sphinx exposes two ports: 9312 (native binary API, what this bundle uses) and 9306 (SphinxQL, MySQL wire protocol). SphinxQL is often easier in Laravel because you can reuse the PDO/query builder:

DB::connection('sphinx')->select("SELECT id, WEIGHT() AS w FROM products_index WHERE MATCH(?) LIMIT 20", [$query]);

Both are valid; the bundle only covers 9312. Pick one and stay consistent.

Indexing is cron, not request-time. The bundle has no indexer. Pattern:

indexer products_index --rotate   # cron every N minutes

Use delta indexes (a delta source with sql_query_range over updated_at) plus a main index merged periodically, otherwise a full reindex on a large table blocks you.

Hydrate IDs back into Eloquent and preserve rank. Sphinx returns only id and weight. Standard flow:

$ids = array_column($result['matches'], 'id');
$models = Product::whereIn('id', $ids)->get()
    ->sortBy(fn($m) => array_search($m->id, $ids))->values();

Filters beat post-filtering. Push price, category_id, in_stock into the Sphinx config as attributes and use $client->setFilter('category_id', [$id]). Do not fetch 10k rows and WHERE them in PHP.

Pagination contract. $client->setLimits($offset, $perPage) and read $result['total_found'] (capped by max_matches, default 1000) — that's your paginator total, not count($matches).

Excerpts for search-result snippets. Call buildExcerpts($docs, 'products_index', $query, ['before_match' => '<em>', 'after_match' => '</em>']). It needs the full text column, so keep a content/name field indexed and fetch it alongside IDs.

Laravel integration tip: if you genuinely want the bundle's API, run Symfony's DI container standalone via symfony/dependency-injection and load the bundle's Extension — note 0.2.5 targets the Symfony 3 container API, so you'd need the Symfony 3.x component line, not 2.x. But realistically, copy the ~80 lines into App\Services\SphinxSearch and add it to a service provider. That's the whole bundle.

Gotchas and Tips

  • Port confusion is the #1 support ticket. 9312 = native API (SphinxClient), 9306 = SphinxQL. Connecting the PHP client to 9306 fails with a protocol error that looks like a daemon crash.
  • Symfony bundle won't boot in Laravel — and 0.2.5 doesn't change that. The release is a framework-compatibility bump (Symfony3), not a Laravel bridge: no ServiceProvider, no config merge, no facade, and the Bundle base class doesn't exist in a Laravel app. Don't composer require this expecting php artisan support — extract the wrapper.
  • 0.2.5 is a version-pin bump, not a feature release. It moves the Symfony constraint forward; the query wrapper, config keys, and SphinxClient construction are unchanged. Nothing in your ported service class needs to change, and it still carries no Sphinx client or protocol improvements.
  • Sphinx is effectively abandoned; use Manticore. Manticore Search is a drop-in replacement speaking both 9312 and 9306, actively maintained. The PHP client still works, so you lose nothing.
  • max_matches silently truncates. Default 1000 — deep pagination returns total_found that ignores anything past it. Set max_matches explicitly or switch to SphinxQL LIMIT/OFFSET with max_matches in config.
  • Escape user input. SPH_MATCH_EXTENDED2 parses @, ~, |, ", -. A raw $request->q can throw or produce garbage. Use $client->escapeString() (the bundle exposes it) and wrap phrases yourself.
  • Config drift kills ranking. charset_table, min_word_len, and morphology = stem_en must match between index and searchd, and the daemon must be restarted (not just reindexed) after config changes. Symptom: a term that works in indexer --all returns zero hits in queries.
  • buildExcerpts needs the index to exist and the field to be in sql_field_string/sql_attr_*. Passing the wrong field name returns false, not an exception — always check the return.
  • Weights are not scores. weight is relative within a result set; don't compare weights across queries. Tune with setFieldWeights(['title' => 10, 'body' => 1]).
  • Reindex/rotate race. indexer --rotate is atomic, but a --all without --rotate leaves the daemon serving the old index until restarted. Automate --rotate and add searchd --status to your healthcheck.
  • Zero stars, zero dependents, no Laravel footprint. Treat it as reference code, not a dependency. Fork the service class, pin sphinxsearch/sphinxsearch, and put Manticore in your Docker compose so your team can reproduce bugs locally.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings