hautelook/solarium-fixtures
Solarium Fixtures provides fixture-loading and index-management helpers for Solarium, making it easier to seed, reset, and tear down Apache Solr test data between PHP integration tests with less boilerplate.
This package is a thin layer that loads fixture files into a Solr core through a Solarium client. It is not Laravel-aware (no service provider, no auto-discovery), and it is unmaintained — its last useful life is as a small helper you wrap yourself.
composer.json constraints first, since it predates Solarium 6 and will conflict with modern solarium/solarium):
composer require hautelook/solarium-fixtures solarium/solarium
vendor/hautelook/solarium-fixtures/ — the whole package is essentially one loader class plus a Tests/ folder. Read the tests first; they are the only reliable documentation of the expected fixture file shape.Client (built from your config/solr.php host/port/core) and a fixtures directory:
$this->app->singleton(\Hautelook\Solarium\Fixtures\FixtureLoader::class, fn () =>
new \Hautelook\Solarium\Fixtures\FixtureLoader(
app(\Solarium\Client::class),
base_path('resources/solr-fixtures')
)
);
solr:seed Artisan command that wipes a local core and loads a handful of JSON fixtures so you can develop search UI without a production Solr dump. That is the highest-value, lowest-risk entry point.Fixture directory convention. Keep one folder per entity or per environment: resources/solr-fixtures/products/*.json, resources/solr-fixtures/categories/*.json. Each fixture file is an array of documents keyed by Solr field names. Because the loader is dumb about schema, your fixture files are your schema documentation — keep them in sync with solr/conf/managed-schema.
Seeding command. Wrap the loader in a command that clears the index first, then loads, then commits:
public function handle(FixtureLoader $loader): int
{
$client = app(\Solarium\Client::class);
$client->createUpdate()->addDeleteQuery('*:*')->addCommit()->execute();
$loader->load('products'); // your wrapper around the package
return self::SUCCESS;
}
Never skip the final commit — Solr will accept documents into the transaction log but not make them searchable until a hard or soft commit lands.
Feature-test fixture lifecycle. Mirror RefreshDatabase with a small trait: in setUp() delete all documents and load the fixture set your test needs, and in tearDown() delete again. This keeps Solr tests hermetic without the package doing any cleanup for you (it does none). Prefer a soft commit in tests to keep the suite fast.
Multi-core / multi-connection. The loader is tied to one Solarium\Client and one core. If you split indexes (products vs. content), register named singletons (solr.products, solr.content) and instantiate a loader per connection rather than adding branching logic inside a shared loader.
Composition with database seeders. Build a DatabaseSeeder-equivalent for Solr that calls the fixture loader after Eloquent seeding, and derive Solr documents from the freshly created records (or from fixtures that share primary keys with the DB seed). This lets you assert join-style behavior across DB + Solr in one test.
composer require fails, either pin Solarium to the constraint the package wants or — more realistically — copy the ~100 lines of loader code into your app (app/Support/Solr/FixtureLoader.php) and drop the dependency. Given zero dependents and no maintenance, vendoring the loader is often the correct call.id field (and even then Solr overwrites by id, but re-runs with different ids accumulate). Always delete-then-load.int field or a nested object into a string silently fails or rejects the whole batch depending on Solr's config. Load small batches when debugging and check $response->getStatus() — the loader usually swallows partial failures.config/ publish. Hard-code paths or expose them via your own config/solr.php with SOLR_HOST, SOLR_PORT, SOLR_CORE — do not read the package's internal assumptions.setUp(), not only tearDown().curl "http://localhost:8983/solr/<core>/select?q=*:*&rows=1". If numFound is zero after a load, your commit never executed; if it's non-zero but filtered queries miss, the issue is analysis/field-type, not the loader.load(string $fixtureSet) / clear() / commit() interface, with the vendored loader behind it. That shields the rest of your app from ever touching a dead package's API.How can I help you explore Laravel packages today?