@@ -670,19 +670,35 @@ following queries:
670670- ` /products?price[lte]=100` — products whose price is less than or equal to 100
671671- ` /products?price[ne]=0` — products whose price is not equal to 0
672672
673- # ## Range Queries (Combining Operators)
673+ # ## Range Queries
674674
675- In 4.4 there is no dedicated `between` operator. To filter within a range, combine `gte` and `lte`
676- (or `gt` and `lt`) in a single request :
675+ ` ComparisonFilter` provides a native `between` operator
676+ (`ApiPlatform\Doctrine\Orm\Filter\ComparisonFilter::OPERATOR_BETWEEN`, value `between`) for range
677+ queries : ` ?property[between]=<min>..<max>` . Both bounds are required, must be numeric, and are
678+ separated by two dots (`..`) :
677679
678680` ` ` http
679- GET /products?price[gte ]=10&price[lte]= 100
681+ GET /products?price[between ]=10.. 100
680682` ` `
681683
682- This returns all products whose price is between 10 and 100 inclusive.
684+ This returns all products whose price is between 10 and 100 inclusive. On Doctrine ORM, it compiles
685+ to a single SQL `BETWEEN` clause :
683686
684- > [!NOTE] Since API Platform 5.0, `ComparisonFilter` also accepts a native `[between]=X..Y` operator
685- > (`?price[between]=10..100`), which emits a single SQL `BETWEEN` clause on Doctrine ORM.
687+ ` ` ` sql
688+ o.price BETWEEN :price_1 AND :price_2
689+ ` ` `
690+
691+ When both bounds are equal (`?price[between]=10..10`), the filter collapses the range to an equality
692+ (`o.price = :price`) instead of a `BETWEEN` clause. On Doctrine MongoDB ODM, which has no native
693+ ` BETWEEN` operator, the same `[between]=X..Y` syntax is translated to the native `gte`/`lte` pair on
694+ the field instead.
695+
696+ ` [between]` only accepts numeric bounds. To range-filter a `DateTime` property, combine `gte` and
697+ ` lte` (or `gt` and `lt`) explicitly instead — see [DateTime Support](#datetime-support) below:
698+
699+ ` ` ` http
700+ GET /events?startDate[gte]=2025-01-01&startDate[lte]=2025-12-31
701+ ` ` `
686702
687703# ## DateTime Support
688704
@@ -766,20 +782,25 @@ Doctrine's type system, which is required for correct comparisons on binary UUID
766782
767783# ## OpenAPI Documentation
768784
769- ` ComparisonFilter` automatically generates five OpenAPI query parameters for each configured
785+ ` ComparisonFilter` automatically generates six OpenAPI query parameters for each configured
770786parameter key, one per operator. For a parameter named `price`, the generated parameters are
771- ` price[gt]` , `price[gte]`, `price[lt]`, `price[lte]`, and `price[ne ]`.
787+ ` price[gt]` , `price[gte]`, `price[lt]`, `price[lte]`, `price[ne]`, and `price[between ]`.
772788
773789# # Date Filter
774790
775791> [!NOTE] `DateFilter` is a kept filter: there is no modern replacement for it.
776- > [`ComparisonFilter`](#comparison-filter) only performs plain `gt`/`gte`/`lt`/`lte`/`ne`
777- > comparisons and does not replicate `DateFilter`'s per-property
792+ > [`ComparisonFilter`](#comparison-filter) performs plain `gt`/`gte`/`lt`/`lte`/`ne` comparisons and
793+ > provides a numeric-only `between` operator, but does not replicate `DateFilter`'s per-property
778794> [`null` management](#managing-null-values), its automatic `\DateTime`/`\DateTimeImmutable` binding
779795> based on the Doctrine column type, its tolerant handling of invalid or empty date values, or its
780796> inclusive `before`/`after` versus exclusive `strictly_before`/`strictly_after` URL vocabulary.
781797> Keep `DateFilter` and declare it through a `QueryParameter`.
782798
799+ Since API Platform 5.0, the ORM and ODM `DateFilter` classes implement `FilterInterface` directly
800+ instead of extending `AbstractFilter`. Their syntax and behavior are unchanged. Both classes were
801+ already final, so this change only affects code that checks or type-hints them as `AbstractFilter`;
802+ use `FilterInterface` or the interface for the capability your code requires instead.
803+
783804The date filter allows filtering a collection by date intervals.
784805
785806Syntax : ` ?property[<after|before|strictly_after|strictly_before>]=value`
@@ -1113,10 +1134,11 @@ It will return all offers with `sold` equals `1`.
11131134
11141135## Range Filter
11151136
1116- > [ !TIP] Consider using [ ` ComparisonFilter ` ] ( #comparison-filter ) wrapping ` ExactFilter ` as a modern
1117- > replacement. ` ComparisonFilter ` does not extend ` AbstractFilter ` , works natively with
1118- > ` QueryParameter ` , and supports range queries by combining ` gte ` and ` lte ` operators (e.g.,
1119- > ` ?price[gte]=10&price[lte]=100 ` ).
1137+ > [ !WARNING] ` RangeFilter ` is ** deprecated** since API Platform 4.4 and will be ** removed in API
1138+ > Platform 6.0** . Use [ ` ComparisonFilter ` ] ( #comparison-filter ) wrapping ` ExactFilter ` instead: it
1139+ > does not extend ` AbstractFilter ` , works natively with ` QueryParameter ` , and covers the same syntax
1140+ > (` gt ` /` gte ` /` lt ` /` lte ` and a native ` [between]=X..Y ` , see [ Range Queries] ( #range-queries ) ). See
1141+ > the [ migration example] ( #example-migrating-a-rangefilter ) below — the URL syntax is unchanged.
11201142
11211143The range filter allows you to filter by a value lower than, greater than, lower than or equal,
11221144greater than or equal and between two values.
@@ -1166,6 +1188,11 @@ You can filter offers by joining two values, for example: `/offers?price[gt]=12.
11661188
11671189## Exists Filter
11681190
1191+ Since API Platform 5.0, the ORM and ODM ` ExistsFilter ` classes implement ` FilterInterface ` directly
1192+ instead of extending ` AbstractFilter ` . Their syntax and behavior are unchanged. Both classes were
1193+ already final, so this change only affects code that checks or type-hints them as ` AbstractFilter ` ;
1194+ use ` FilterInterface ` or the interface for the capability your code requires instead.
1195+
11691196The "exists" filter allows you to select items based on a nullable field value. It will also check
11701197the emptiness of a collection association.
11711198
@@ -1989,6 +2016,13 @@ It means that the filter will be **silently** ignored if the property:
19892016A filter that implements the `ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface`
19902017interface can be decorated :
19912018
2019+ > [!NOTE] Since API Platform 5.0, `PropertyAwareFilterInterface` declares both
2020+ > `setProperties(array $properties): void` and `getProperties(): ?array` (the getter was previously
2021+ > commented out on the interface and only enforced by convention). A class implementing the
2022+ > interface directly must now implement both methods, or a fatal error is raised. `getProperties()`
2023+ > returns the property map currently configured on the filter, or `null` when the filter is not
2024+ > restricted to specific properties (it then applies to all of them).
2025+
19922026` ` ` php
19932027namespace App\D octrine\F ilter;
19942028
@@ -1999,12 +2033,22 @@ use ApiPlatform\Metadata\Operation;
19992033use Doctrine\O RM\Q ueryBuilder;
20002034use Symfony\C omponent\D ependencyInjection\A ttribute\A utowire;
20012035
2002- final class SearchTextAndDateFilter implements FilterInterface
2036+ final class SearchTextAndDateFilter implements FilterInterface, PropertyAwareFilterInterface
20032037{
20042038 public function __construct(#[Autowire('@api_platform.doctrine.orm.search_filter.instance')] readonly FilterInterface $searchFilter, #[Autowire('@api_platform.doctrine.orm.date_filter.instance')] readonly FilterInterface $dateFilter, protected ?array $properties = null, private array $dateFilterProperties = [], private array $searchFilterProperties = [])
20052039 {
20062040 }
20072041
2042+ public function setProperties(array $properties): void
2043+ {
2044+ $this->properties = $properties;
2045+ }
2046+
2047+ public function getProperties(): ?array
2048+ {
2049+ return $this->properties;
2050+ }
2051+
20082052 // This function is only used to hook in documentation generators (supported by Swagger and Hydra)
20092053 public function getDescription(string $resourceClass): array
20102054 {
0 commit comments