Skip to content

Commit

Permalink
docs: parameters documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Apr 29, 2024
1 parent 3811502 commit 63820c1
Showing 1 changed file with 192 additions and 0 deletions.
192 changes: 192 additions & 0 deletions core/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -1660,3 +1660,195 @@ The next filters are not related to how the data is fetched but rather to how th
#[ApiFilter(PropertyFilter::class, arguments: ['parameterName' => 'foobar'])]
#[ApiFilter(GroupFilter::class, arguments: ['parameterName' => 'foobargroups'])]
```

## Parameters

An option exists to declare parameters on a Resource or an Operation through the `parameters` property.

```php
namespace App\ApiResource;

use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\QueryParameter;

// This parameter "page" works only on /books
#[GetCollection(uriTemplate: '/books', parameters: ['page' => new QueryParameter])]
// This parameter is available on every operations, key is mandatory
#[QueryParameter(key: 'q', property: 'hydra:freetextQuery')]
class Book {}
```

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.

### Alter the Operation via a parameter

A parameter can alter the current Operation context, to do so use a `ApiPlatform\State\ParameterProviderInterface`:

```php
class GroupsParameterProvider implements ParameterProviderInterface {
public function provider(Parameter $parameter, array $uriVariables = [], array $context = []): HttpOperation
{
$request = $context['request'];
return $context['operation']->withNormalizationContext(['groups' => $request->query->all('groups')]);
}
}
```

Then plug this provider on your parameter:

```php
namespace App\ApiResource;

use ApiPlatform\Metadata\HeaderParameter;

#[Get(parameters: ['groups' => new HeaderParameter(provider: GroupsParameterProvider::class)])]
class Book {
public string $id;
}
```

If you don't have autoconfiguration enabled, declare the parameter as a tagged service:

```yaml
services:
ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider:
tags:
- name: 'api_platform.parameter_provider'
key: 'ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider'
```

### Call a filter

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:

```yaml
# config/services.yaml
services:
offer.order_filter:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { id: ~, name: ~ }
$orderParameterName: order
tags: [ 'api_platform.filter' ]
```

We can use this filter specifying we want a query parameter with the `:property` placeholder:

```php
namespace App\ApiResource;

#[GetCollection(
uriTemplate: 'orders',
parameters: [
'order[:property]' => new QueryParameter(filter: 'offer.order_filter'),
]
)
class Offer {
public string $id;
public string $name;
}
```

### Decorate a Doctrine filter

A filter that implements the `ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface` interface can be decorated:

```php
namespace App\Doctrine\Filter;

use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\FilterInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

final class SearchTextAndDateFilter implements FilterInterface
{
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 = [])
{
}

// This function is only used to hook in documentation generators (supported by Swagger and Hydra)
public function getDescription(string $resourceClass): array
{
if ($this->searchFilter instanceof PropertyAwareFilterInterface) {
$this->searchFilter->setProperties($this->searchFilterProperties);
}
if ($this->dateFilter instanceof PropertyAwareFilterInterface) {
$this->dateFilter->setProperties($this->dateFilterProperties);
}

return array_merge($this->searchFilter->getDescription($resourceClass), $this->dateFilter->getDescription($resourceClass));
}

public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
{
if ($this->searchFilter instanceof PropertyAwareFilterInterface) {
$this->searchFilter->setProperties($this->searchFilterProperties);
}
if ($this->dateFilter instanceof PropertyAwareFilterInterface) {
$this->dateFilter->setProperties($this->dateFilterProperties);
}

$this->searchFilter->apply($queryBuilder, $queryNameGenerator, $resourceClass, $operation, ['filters' => $context['filters']['searchOnTextAndDate']] + $context);
$this->dateFilter->apply($queryBuilder, $queryNameGenerator, $resourceClass, $operation, ['filters' => $context['filters']['searchOnTextAndDate']] + $context);
}
}
```

This can be used with parameters using attributes:

```php
namespace App\Entity;

#[GetCollection(
uriTemplate: 'search_filter_parameter{._format}',
parameters: [
'searchOnTextAndDate[:property]' => new QueryParameter(filter: 'app_filter_date_and_search'),
]
)]
// Note that we link the parameter filter and this filter using the "alias" option:
#[ApiFilter(SearchTextAndDateFilter::class, alias: 'app_filter_date_and_search', properties: ['foo', 'createdAt'], arguments: ['dateFilterProperties' => ['createdAt' => 'exclude_null'], 'searchFilterProperties' => ['foo' => 'exact']])]
#[ORM\Entity]
class SearchFilterParameter
{
/**
* @var int The id
*/
#[ORM\Column(type: 'integer')]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
#[ORM\Column(type: 'string')]
private string $foo = '';

#[ORM\Column(type: 'datetime_immutable', nullable: true)]
private ?\DateTimeImmutable $createdAt = null;

public function getId(): ?int
{
return $this->id;
}

public function getFoo(): string
{
return $this->foo;
}

public function setFoo(string $foo): void
{
$this->foo = $foo;
}

public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}

public function setCreatedAt(\DateTimeImmutable $createdAt): void
{
$this->createdAt = $createdAt;
}
}
```

0 comments on commit 63820c1

Please sign in to comment.