Skip to content

Commit 880e2ef

Browse files
authored
docs(filters): document 5.0 changes
1 parent 615e982 commit 880e2ef

3 files changed

Lines changed: 72 additions & 29 deletions

File tree

‎core/doctrine-filters.md‎

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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
770786
parameter 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+
783804
The date filter allows filtering a collection by date intervals.
784805

785806
Syntax: `?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
11211143
The range filter allows you to filter by a value lower than, greater than, lower than or equal,
11221144
greater 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+
11691196
The "exists" filter allows you to select items based on a nullable field value. It will also check
11701197
the emptiness of a collection association.
11711198

@@ -1989,6 +2016,13 @@ It means that the filter will be **silently** ignored if the property:
19892016
A filter that implements the `ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface`
19902017
interface 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
19932027
namespace App\Doctrine\Filter;
19942028
@@ -1999,12 +2033,22 @@ use ApiPlatform\Metadata\Operation;
19992033
use Doctrine\ORM\QueryBuilder;
20002034
use Symfony\Component\DependencyInjection\Attribute\Autowire;
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
{

‎core/filters.md‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ a new instance:
6868
associations.
6969
- Usage: `new QueryParameter(filter: IriFilter::class)`
7070
- **`ComparisonFilter`**: A decorator that wraps an equality filter (`ExactFilter`, `UuidFilter`) to
71-
add `gt`, `gte`, `lt`, `lte`, and `ne` operators. Recommended for numeric comparisons; in 5.0 it
72-
also gains a native `[between]=X..Y` operator. (`DateFilter` and `RangeFilter` are kept as drop-in
73-
filters — see below.)
71+
add `gt`, `gte`, `lt`, `lte`, `ne`, and a native `between` (`[between]=X..Y`) operator.
72+
Recommended for numeric comparisons. (`DateFilter` is kept as a drop-in filter — see below;
73+
`RangeFilter` is deprecated in its favor.)
7474
- Usage:
7575
`new QueryParameter(filter: new ComparisonFilter(new ExactFilter()), property: 'price')`
7676
- **`FreeTextQueryFilter`**: Applies a filter across multiple properties using a single parameter.
@@ -89,7 +89,8 @@ a new instance:
8989
- **`NumericFilter`**: For numeric field filtering (legacy, `ExactFilter` or `ComparisonFilter` is
9090
recommended instead).
9191
- Usage: `new QueryParameter(filter: NumericFilter::class)`
92-
- **`RangeFilter`**: For range-based filtering (legacy, `ComparisonFilter` is recommended instead).
92+
- **`RangeFilter`**: For range-based filtering. **Deprecated since 4.4, removed in 6.0** — use
93+
`ComparisonFilter` wrapping `ExactFilter` instead.
9394
- Usage: `new QueryParameter(filter: RangeFilter::class)`
9495
- **`ExistsFilter`**: For checking existence of nullable values.
9596
- Usage: `new QueryParameter(filter: ExistsFilter::class)`
@@ -753,12 +754,8 @@ The `IriConverterParameterProvider` supports the following options in `extraProp
753754

754755
### `ReadLinkParameterProvider`
755756

756-
This provider must be enabled before it can be used.
757-
758-
```yaml
759-
api_platform:
760-
enable_link_security: true
761-
```
757+
Security on `Link` is always enabled since API Platform 5.0; the previous `enable_link_security`
758+
flag has been removed and no longer needs to be configured.
762759

763760
This provider fetches a linked resource from a given identifier. This is useful when you need to
764761
load a related entity to use later, for example in your own state provider. When you have an API

‎core/jsonapi.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ For details on enabling formats, see [content negotiation](content-negotiation.m
88

99
## Entity Identifiers as Resource IDs
1010

11-
We recommend configuring API Platform to use entity identifiers as the `id` field of JSON:API
12-
resource objects. This will become the default in 5.x:
11+
Since API Platform 5.0, entity identifiers are used as the `id` field of JSON:API resource objects
12+
by default (`use_iri_as_id` defaults to `false`). If you are upgrading from an earlier version and
13+
relied on the previous default (the IRI as the JSON:API `id`), see the
14+
[upgrade guide](upgrade-guide.md) for the migration path.
1315

1416
```yaml
1517
# config/packages/api_platform.yaml
1618
api_platform:
1719
jsonapi:
18-
use_iri_as_id: false
20+
use_iri_as_id: false # the default since API Platform 5.0
1921
```
2022
2123
With this configuration, the JSON:API `id` field contains the entity identifier (e.g., `"10"`)

0 commit comments

Comments
 (0)