Skip to content

[Draft] Add Meilisearch support (src/Meilisearch) - #8443

Draft
tacman wants to merge 3 commits into
api-platform:mainfrom
tacman:meilisearch
Draft

[Draft] Add Meilisearch support (src/Meilisearch)#8443
tacman wants to merge 3 commits into
api-platform:mainfrom
tacman:meilisearch

Conversation

@tacman

@tacman tacman commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Title: [Draft] Add Meilisearch support (src/Meilisearch)

Body:

Addresses #6222.

Adds api-platform/meilisearch, modeled directly on api-platform/elasticsearch's architecture: State/{CollectionProvider,ItemProvider,Options}, a Metadata/Resource/Factory decorator that auto-assigns the right provider from stateOptions (no provider: needed, same as the ES bridge), and the matching Configuration/ApiPlatformExtension/Resources/config/meilisearch.php bundle wiring.

What's different from the Elasticsearch bridge, and why

Meilisearch's API is simpler than Elasticsearch's on two axes that show up directly in the code:

  • Client/exceptions: one official client (meilisearch/meilisearch-php, MIT), one ApiException with a typed httpStatus — no V7Client|Client|OpenSearchClient union, no juggling three different 404 exception classes.
  • Query shape: Meilisearch takes flat search parameters (q, a single filter expression string, sort, facets, limit/offset), not a nested query-DSL body. RequestParametersCollectionExtensionInterface/FilterInterface operate on that flat array — filter composition is AND-joining expression strings rather than merging JSON bool/must trees.

Scope of this draft

  • REST only — the metadata factory decorator doesn't touch GraphQL operations yet (ES's does).
  • Two filters: SearchFilter (free text → q) and TermFilter (exact-match/facet → filter expression). No range/geo filters yet.
  • No index-settings management. Meilisearch requires filterableAttributes/sortableAttributes pre-declared on the index or a query 400s — this is the caller's responsibility here, same as it would be for whatever indexes the documents in the first place.
  • meilisearch/meilisearch-php: ^2.0 — currently only satisfiable via the v2 beta line (dev-main, aliased to 2.0.0; see discussion on Add support for Meilisearch #6222 about whether that's acceptable for a first release).

Verification

Wired into a real app against a live 9.7k-document Meilisearch index (movie dataset): free-text search with typo tolerance, facet filtering (?genres[]=Comedy&year=1995), and pagination all confirmed correct through a real GetCollection operation, EXPLAIN-equivalent traced back to Meilisearch's own query engine (not mocked). Functional tests against a Meilisearch service container are the next step before this comes out of draft — flagging that gap explicitly rather than claiming full coverage.

Opening as a draft to get architecture-level feedback (see the three questions on #6222) before investing in bundle-level tests/CI/docs polish.

tacman added 3 commits August 8, 2026 07:18
Mirrors api-platform/elasticsearch's architecture (per-operation Options
value object + auto-provider-assignment metadata factory decorator +
CollectionProvider/ItemProvider), simplified where Meilisearch's single
client and flat search-parameters model allow it:

- One official client (meilisearch/meilisearch-php), one exception type
  (ApiException with a typed httpStatus) -- no client-SDK union type.
- RequestParametersCollectionExtensionInterface/FilterInterface operate on
  a flat params array (q, filter, sort, facets, limit, offset) instead of
  a nested query-DSL body; filter composition is AND-joining expression
  strings instead of merging JSON bool/must trees.

Symfony bundle wiring (api_platform.meilisearch.*) added to Configuration/
ApiPlatformExtension, mirroring the elasticsearch.* section.

v1 scope: REST only (no GraphQL operations in the auto-provider factory),
two filters (SearchFilter for free text, TermFilter for exact-match
facets), no index-settings reconciliation (filterableAttributes/
sortableAttributes are the caller's responsibility). See src/Meilisearch/README.md.
ParameterValidationResourceMetadataCollectionFactory still calls
getDescription() unconditionally on any filter referenced via an
operation's filters:, even though that method is @deprecated in 4.2/
to-be-removed-in-5.0 on ApiPlatform\Metadata\FilterInterface. Discovered
by actually wiring this into a real app (meili) rather than just reading
the ES source -- ES's own AbstractSearchFilter implements it too, I'd
missed porting it when simplifying the base class.
Mirrors the mocking style already established by
src/Doctrine/Orm/Tests/State/{CollectionProvider,ItemProvider}Test.php
(PHPUnit createMock/prophecy, no live service) rather than inventing a
Docker-based integration-test convention this monorepo doesn't otherwise
use for equivalent Provider code -- src/Elasticsearch/Tests notably has
no CollectionProvider/ItemProvider tests at all, so this is net-new
coverage beyond what the Elasticsearch bridge itself carries.

Meilisearch\Endpoints\Index is final (can't be mocked directly): tests
construct a real Index wired to a mocked Http transport instead, and
mock Client (not final) to hand that Index back from index(). Verified
exact request/response shapes against the real installed client rather
than assumed.

Also fixes composer.json's meilisearch-php constraint: ^2.0 resolved to
the tagged v2.0.0-beta.7, which predates the Endpoints\Index class this
package depends on -- only unreleased dev-main has it. Confirms the
version-stability caveat raised in the api-platform#6222 discussion
is concrete, not hypothetical.

41 tests, 45 assertions, all passing (src/Meilisearch, scoped composer install).
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.

1 participant