Skip to content

Upgrade algolia/algoliasearch-client-php to 4.x - #1835

Merged
Seldaek merged 4 commits into
composer:mainfrom
Seldaek:algolia-client-v4
Sep 7, 2026
Merged

Upgrade algolia/algoliasearch-client-php to 4.x#1835
Seldaek merged 4 commits into
composer:mainfrom
Seldaek:algolia-client-v4

Conversation

@Seldaek

@Seldaek Seldaek commented Sep 7, 2026

Copy link
Copy Markdown
Member

v4 removes initIndex() and the SearchIndex object: every operation is now a method on the client taking the index name. Rather than translate each call site, all contact with the client moves behind App\Search\PackageIndex, so a future client upgrade touches one class and tests stop subclassing vendor code.

Search parameters now go in the request body argument rather than the request options. v3 folded unrecognised request options into the body; v4 discards them without complaint, which would have silently dropped filters and pagination. Query::getOptions() is renamed getSearchParams() so the two are not confused.

packagist:index --force is disabled. It called $index->clear(), which never existed on the v3 client either, so it has always died before clearing anything. Pointing it at clearObjects() would genuinely empty the live index for the hours a full reindex takes, so that wants doing atomically as its own change. --all still reindexes everything in place.

packagist:clean-index now browses with a cursor instead of paging by hand. The old loop drifted every time it deleted a record and could not see past paginationLimitedTo, so it only ever examined the first 300 of the ~557 stale virtual packages. It also checks each record's type before deleting, so it stays safe even if the query's filters were to stop applying.

The client is registered lazily because it throws when constructed without credentials. PackageManager depends on it transitively, so every package page would otherwise fail for anyone with no Algolia config; now only search itself degrades, and .env needs no placeholder credentials.

saveRecords() rejects records with no objectID, which v3 did client-side. v4's saveObjects() would instead let Algolia generate one, creating a record we could never update or delete again.

WebController and PackageManager also catch \InvalidArgumentException, which v4 throws for missing required parameters and for malformed response bodies.

v4 removes initIndex() and the SearchIndex object: every operation is now a
method on the client taking the index name. Rather than translate each call
site, all contact with the client moves behind App\Search\PackageIndex, so a
future client upgrade touches one class and tests stop subclassing vendor code.

Search parameters now go in the request body argument rather than the request
options. v3 folded unrecognised request options into the body; v4 discards them
without complaint, which would have silently dropped filters and pagination.
Query::getOptions() is renamed getSearchParams() so the two are not confused.

packagist:index --force is disabled. It called $index->clear(), which never
existed on the v3 client either, so it has always died before clearing
anything. Pointing it at clearObjects() would genuinely empty the live index
for the hours a full reindex takes, so that wants doing atomically as its own
change. --all still reindexes everything in place.

packagist:clean-index now browses with a cursor instead of paging by hand. The
old loop drifted every time it deleted a record and could not see past
paginationLimitedTo, so it only ever examined the first 300 of the ~557 stale
virtual packages. It also checks each record's type before deleting, so it stays
safe even if the query's filters were to stop applying.

The client is registered lazily because it throws when constructed without
credentials. PackageManager depends on it transitively, so every package page
would otherwise fail for anyone with no Algolia config; now only search itself
degrades, and .env needs no placeholder credentials.

saveRecords() rejects records with no objectID, which v3 did client-side. v4's
saveObjects() would instead let Algolia generate one, creating a record we could
never update or delete again.

WebController and PackageManager also catch \InvalidArgumentException, which v4
throws for missing required parameters and for malformed response bodies.
@private-packagist

private-packagist Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

composer.lock

Package changes

Package Operation From To About
algolia/algoliasearch-client-php upgrade 3.4.2 4.47.0 diff
guzzlehttp/guzzle upgrade 7.15.3 7.15.5 diff
guzzlehttp/promises upgrade 2.5.2 2.5.3 diff
guzzlehttp/psr7 upgrade 2.13.0 2.13.1 diff

Settings · Docs · Powered by Private Packagist

@Seldaek
Seldaek marked this pull request as ready for review September 7, 2026 08:51
Comment thread src/Search/PackageIndex.php Outdated
Comment thread src/Search/PackageIndex.php Outdated
Comment thread src/Search/PackageIndex.php Outdated
Addresses review feedback on PackageIndex: instead of accepting and returning
bare array<string, mixed>, the interface now declares PackageRecord,
SearchParams, BrowseParams and SearchResponse type aliases, and the two record
producers in IndexPackagesCommand declare PackageRecord as their return type.

objectID is now enforced statically rather than only by the runtime guard in
saveRecords(): dropping it from createSearchableProvider() fails analysis with
"Array does not have offset 'objectID'". The runtime guard stays, since the
interface is also reachable from code phpstan cannot see through.

The shapes are unsealed (...<string, mixed>), because the search API takes far
more parameters than we pass and records gain attributes over time. Search and
browse get separate parameter types: browse takes no query. Search responses
keep their hits loose, as /search.json and clean-index query for different
things and narrow accordingly.

Typing the response also surfaced a lie in the transformer's existing docblock:
it declared hits as array{id: int, meta: array{...}}, but virtual-package hits
carry a string id and no meta at all, as tests/Search/results/search-with-virtual
shows. That went unnoticed because v3's search() returned untyped mixed. The
type is corrected and the meta lookup no longer assumes the key is present.
@private-packagist

Copy link
Copy Markdown
Contributor

The composer.lock diff comment has been updated to reflect new changes in this PR.

@Seldaek
Seldaek merged commit 3ab4fc1 into composer:main Sep 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants