Skip to content

Commit 41d3a28

Browse files
committed
docs: parameters documentation
1 parent bd12187 commit 41d3a28

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed

core/filters.md

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,3 +1660,195 @@ The next filters are not related to how the data is fetched but rather to how th
16601660
#[ApiFilter(PropertyFilter::class, arguments: ['parameterName' => 'foobar'])]
16611661
#[ApiFilter(GroupFilter::class, arguments: ['parameterName' => 'foobargroups'])]
16621662
```
1663+
1664+
## Parameters
1665+
1666+
An option exists to declare parameters on a Resource or an Operation through the `parameters` property.
1667+
1668+
```php
1669+
namespace App\ApiResource;
1670+
1671+
use ApiPlatform\Metadata\GetCollection;
1672+
use ApiPlatform\Metadata\QueryParameter;
1673+
1674+
// This parameter "page" works only on /books
1675+
#[GetCollection(uriTemplate: '/books', parameters: ['page' => new QueryParameter])]
1676+
// This parameter is available on every operations, key is mandatory
1677+
#[QueryParameter(key: 'q', property: 'hydra:freetextQuery')]
1678+
class Book {}
1679+
```
1680+
1681+
Note that `property` is used to document the Hydra view. You can also specify an [OpenAPI Parameter](https://api-platform.com/docs/references/OpenApi/Model/Parameter/) if needed.
1682+
1683+
### Alter the Operation via a parameter
1684+
1685+
A parameter can alter the current Operation context, to do so use a `ApiPlatform\State\ParameterProviderInterface`:
1686+
1687+
```php
1688+
class GroupsParameterProvider implements ParameterProviderInterface {
1689+
public function provider(Parameter $parameter, array $uriVariables = [], array $context = []): HttpOperation
1690+
{
1691+
$request = $context['request'];
1692+
return $context['operation']->withNormalizationContext(['groups' => $request->query->all('groups')]);
1693+
}
1694+
}
1695+
```
1696+
1697+
Then plug this provider on your parameter:
1698+
1699+
```php
1700+
namespace App\ApiResource;
1701+
1702+
use ApiPlatform\Metadata\HeaderParameter;
1703+
1704+
#[Get(parameters: ['groups' => new HeaderParameter(provider: GroupsParameterProvider::class)])]
1705+
class Book {
1706+
public string $id;
1707+
}
1708+
```
1709+
1710+
If you don't have autoconfiguration enabled, declare the parameter as a tagged service:
1711+
1712+
```yaml
1713+
services:
1714+
ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider:
1715+
tags:
1716+
- name: 'api_platform.parameter_provider'
1717+
key: 'ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider'
1718+
```
1719+
1720+
### Call a filter
1721+
1722+
A Parameter can also call a filter and works on filters that impact the data persistence layer (Doctrine ORM and ODM filters are supported). Let's assume, that we have an Order filter declared:
1723+
1724+
```yaml
1725+
# config/services.yaml
1726+
services:
1727+
offer.order_filter:
1728+
parent: 'api_platform.doctrine.orm.order_filter'
1729+
arguments:
1730+
$properties: { id: ~, name: ~ }
1731+
$orderParameterName: order
1732+
tags: [ 'api_platform.filter' ]
1733+
```
1734+
1735+
We can use this filter specifying we want a query parameter with the `:property` placeholder:
1736+
1737+
```php
1738+
namespace App\ApiResource;
1739+
1740+
#[GetCollection(
1741+
uriTemplate: 'orders',
1742+
parameters: [
1743+
'order[:property]' => new QueryParameter(filter: 'offer.order_filter'),
1744+
]
1745+
)
1746+
class Offer {
1747+
public string $id;
1748+
public string $name;
1749+
}
1750+
```
1751+
1752+
### Decorate a Doctrine filter
1753+
1754+
A filter that implements the `ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface` interface can be decorated:
1755+
1756+
```php
1757+
namespace App\Doctrine\Filter;
1758+
1759+
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
1760+
use ApiPlatform\Doctrine\Orm\Filter\FilterInterface;
1761+
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
1762+
use ApiPlatform\Metadata\Operation;
1763+
use Doctrine\ORM\QueryBuilder;
1764+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
1765+
1766+
final class SearchTextAndDateFilter implements FilterInterface
1767+
{
1768+
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 = [])
1769+
{
1770+
}
1771+
1772+
// This function is only used to hook in documentation generators (supported by Swagger and Hydra)
1773+
public function getDescription(string $resourceClass): array
1774+
{
1775+
if ($this->searchFilter instanceof PropertyAwareFilterInterface) {
1776+
$this->searchFilter->setProperties($this->searchFilterProperties);
1777+
}
1778+
if ($this->dateFilter instanceof PropertyAwareFilterInterface) {
1779+
$this->dateFilter->setProperties($this->dateFilterProperties);
1780+
}
1781+
1782+
return array_merge($this->searchFilter->getDescription($resourceClass), $this->dateFilter->getDescription($resourceClass));
1783+
}
1784+
1785+
public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
1786+
{
1787+
if ($this->searchFilter instanceof PropertyAwareFilterInterface) {
1788+
$this->searchFilter->setProperties($this->searchFilterProperties);
1789+
}
1790+
if ($this->dateFilter instanceof PropertyAwareFilterInterface) {
1791+
$this->dateFilter->setProperties($this->dateFilterProperties);
1792+
}
1793+
1794+
$this->searchFilter->apply($queryBuilder, $queryNameGenerator, $resourceClass, $operation, ['filters' => $context['filters']['searchOnTextAndDate']] + $context);
1795+
$this->dateFilter->apply($queryBuilder, $queryNameGenerator, $resourceClass, $operation, ['filters' => $context['filters']['searchOnTextAndDate']] + $context);
1796+
}
1797+
}
1798+
```
1799+
1800+
This can be used with parameters using attributes:
1801+
1802+
```php
1803+
namespace App\Entity;
1804+
1805+
#[GetCollection(
1806+
uriTemplate: 'search_filter_parameter{._format}',
1807+
parameters: [
1808+
'searchOnTextAndDate[:property]' => new QueryParameter(filter: 'app_filter_date_and_search'),
1809+
]
1810+
)]
1811+
// Note that we link the parameter filter and this filter using the "alias" option:
1812+
#[ApiFilter(SearchTextAndDateFilter::class, alias: 'app_filter_date_and_search', properties: ['foo', 'createdAt'], arguments: ['dateFilterProperties' => ['createdAt' => 'exclude_null'], 'searchFilterProperties' => ['foo' => 'exact']])]
1813+
#[ORM\Entity]
1814+
class SearchFilterParameter
1815+
{
1816+
/**
1817+
* @var int The id
1818+
*/
1819+
#[ORM\Column(type: 'integer')]
1820+
#[ORM\Id]
1821+
#[ORM\GeneratedValue(strategy: 'AUTO')]
1822+
private ?int $id = null;
1823+
#[ORM\Column(type: 'string')]
1824+
private string $foo = '';
1825+
1826+
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
1827+
private ?\DateTimeImmutable $createdAt = null;
1828+
1829+
public function getId(): ?int
1830+
{
1831+
return $this->id;
1832+
}
1833+
1834+
public function getFoo(): string
1835+
{
1836+
return $this->foo;
1837+
}
1838+
1839+
public function setFoo(string $foo): void
1840+
{
1841+
$this->foo = $foo;
1842+
}
1843+
1844+
public function getCreatedAt(): ?\DateTimeImmutable
1845+
{
1846+
return $this->createdAt;
1847+
}
1848+
1849+
public function setCreatedAt(\DateTimeImmutable $createdAt): void
1850+
{
1851+
$this->createdAt = $createdAt;
1852+
}
1853+
}
1854+
```

0 commit comments

Comments
 (0)