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

Solarium Async Plugin Laravel Package

shieldo/solarium-async-plugin

A Solarium plugin that adds asynchronous query support to the PHP Solr client, letting you dispatch multiple requests concurrently and collect responses later. Useful for speeding up batch searches and reducing wait time when querying Solr from Laravel or plain PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Before writing a line of code, verify the compatibility window. This plugin targets the HTTPlug era of Solarium (php-http/httplug, Http\Promise\Promise as the async contract). Solarium 6+ moved to PSR-18/PSR-7, so the plugin is a non-starter there. Read the package's composer.json first and pin solarium/solarium to whatever major it declares — do not let composer update drift you across that boundary.

Install the plugin plus an adapter that actually implements Http\Client\HttpAsyncClient:

composer require shieldo/solarium-async-plugin \
                 php-http/guzzle7-adapter \
                 solarium/solarium:^5.0

A sync-only PSR-18 client will install fine and then explode at runtime on sendAsyncRequest(). Confirm the async interface before you build on it.

Wire it up — the plugin registers like any Solarium plugin, either via config ('plugin' => ['async' => ['plugin' => ...]]) or programmatically:

use Solarium\Client;
use Solarium\Core\Client\Adapter\Http;
use Http\Adapter\Guzzle7\Client as GuzzleAdapter;
use Symfony\Component\EventDispatcher\EventDispatcher;

$adapter = new Http(new GuzzleAdapter(new \GuzzleHttp\Client()), new EventDispatcher());
$client  = new Client($adapter, new EventDispatcher());

$client->registerPlugin('async', new \Shieldo\SolariumAsyncPlugin\AsyncPlugin());

Where to look first: the plugin class extends Solarium\Core\Plugin\AbstractPlugin; read its initPlugin() to see which Solarium\Core\Event\Events hooks it attaches to, then read its public methods to confirm the async entry point signature before you build abstractions around it.

First use case: fan-out on a search page. One page needs a select for documents, a second select with a different filter for facet counts, and a suggest query. Sequentially that's three round-trips; dispatched together and waited on at the end, it's one.

Implementation Patterns

Fan-out / fan-in. Dispatch everything first, resolve afterwards. The requests are in flight the moment you call the async execute; wait() only blocks for completion, so resolve in a second loop:

$promises = [];
foreach ($queries as $key => $query) {
    $promises[$key] = $plugin->executeAsync($query);   // confirm exact method name in src/
}

$results = [];
foreach ($promises as $key => $promise) {
    $results[$key] = $promise->wait();                 // Solarium\QueryType\*\Result
}

Bound the concurrency. Do not fan out 200 queries. Solr queues them, your client holds sockets, and a slow query starves the rest. Chunk into batches of 5–10 and \Http\Promise\settle() or wait per batch.

Non-blocking callbacks. When you want to process as results land rather than after the last one, hang handlers off the promise:

$promise->then(
    fn ($result) => $this->hydrate($result),
    fn (\Throwable $e) => $this->logger->error('solr async failed', ['e' => $e])
);

Shared client, one registration. Register the plugin once in your DI container alongside the Solarium\Client singleton. The plugin is effectively stateless; rebuilding clients per request costs you warm connections.

Test with a mock async client. Http\Mock\Client implements the async interface and returns already-resolved promises, so you can assert on wait() results synchronously and keep the suite deterministic.

Bridge to your request pipeline. Because Solarium's response parsing runs inside the promise resolution, a then() chain is the natural place to push normalized hits into your own DTOs, keeping Solarium result objects out of your controllers.

Gotchas and Tips

  • The version cliff is the whole ballgame. Solarium 6 dropped HTTPlug for PSR-18. If you are upgrading Solarium, this package is dead weight — replace it by building requests through AdapterInterface::createRequest() and sending them with your own async client. Roughly the same benefit, no unmaintained dependency.
  • Adapters lie about async. php-http/guzzle7-adapter implements both sync and async; some clients only implement HttpClient. The failure is a runtime exception at first dispatch, not a Composer conflict. Check instanceof HttpAsyncClient in a boot-time assertion.
  • Promises don't run in the background. With curl_multi the transfer progresses when the loop is ticked — i.e. while you wait(). "Fire and forget, collect later in a cron" is not what this gives you.
  • Result objects are incomplete until wait(). Calling getNumFound() on a half-resolved result throws or returns garbage. Only touch results inside the resolution path.
  • Exception types get wrapped by the promise machinery. Catch \Throwable at the wait() boundary, inspect getPrevious(), and log the raw PSR-7 response body in the rejection handler — a Solr 400 is far easier to diagnose from the body than from a generic transport exception.
  • Async makes Solarium's own event log interleave. If you use the event logger plugin for debugging, timestamp events yourself or run the queries sequentially to reproduce a failure.
  • Treat it as unmaintained. One star, zero dependents. Vendor-fork it via a Composer path or VCS repository if you need a patch, and put a smoke test around the async execute path so a Solarium or adapter bump fails loudly in CI rather than in production.
  • Extension point: if the shipped plugin doesn't cover your route, subclass it and override initPlugin() to attach to Events::PRE_EXECUTE_REQUEST yourself — that's the seam where request creation and dispatch are separated, and it's the least invasive place to add metrics, retries, or endpoint routing.
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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle