Skip to content

Commit 94119bd

Browse files
committed
Add filters support for Swagger
1 parent 113eb39 commit 94119bd

File tree

6 files changed

+242
-111
lines changed

6 files changed

+242
-111
lines changed

features/swagger/doc.feature

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,14 @@ Feature: Documentation support
5151
And the Swagger path "/api/custom-call/{id}" exists
5252
And the JSON node "paths./api/custom-call/{id}.get" should exist
5353
And the JSON node "paths./api/custom-call/{id}.put" should exist
54-
5554
# Properties
5655
And "id" property exists for the Swagger class "Dummy"
5756
And "name" property is required for Swagger class "Dummy"
57+
# Filters
58+
And the JSON node "paths./dummies.get.parameters[0].name" should be equal to "id"
59+
And the JSON node "paths./dummies.get.parameters[0].in" should be equal to "query"
60+
And the JSON node "paths./dummies.get.parameters[0].required" should be false
61+
And the JSON node "paths./dummies.get.parameters[0].type" should be equal to "integer"
5862

5963
Scenario: Swagger UI is enabled for the doc endpoint
6064
Given I add "Accept" header equal to "text/html"

src/Bridge/Symfony/Bundle/Resources/config/swagger.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<argument type="service" id="api_platform.operation_method_resolver" />
1515
<argument type="service" id="api_platform.operation_path_resolver" />
1616
<argument type="service" id="api_platform.router" />
17+
<argument type="service" id="api_platform.filters" />
1718

1819
<tag name="serializer.normalizer" priority="16" />
1920
</service>

src/Hydra/Serializer/CollectionFiltersNormalizer.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public function normalize($object, $format = null, array $context = [])
6363
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
6464

6565
$operationName = $context['collection_operation_name'] ?? null;
66-
6766
if (null === $operationName) {
6867
$resourceFilters = $resourceMetadata->getAttribute('filters', []);
6968
} else {

src/Swagger/Serializer/DocumentationNormalizer.php

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace ApiPlatform\Core\Swagger\Serializer;
1313

14+
use ApiPlatform\Core\Api\FilterCollection;
1415
use ApiPlatform\Core\Api\OperationMethodResolverInterface;
1516
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
1617
use ApiPlatform\Core\Api\UrlGeneratorInterface;
@@ -43,8 +44,9 @@ final class DocumentationNormalizer implements NormalizerInterface
4344
private $operationMethodResolver;
4445
private $operationPathResolver;
4546
private $urlGenerator;
47+
private $filterCollection;
4648

47-
public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceClassResolverInterface $resourceClassResolver, OperationMethodResolverInterface $operationMethodResolver, OperationPathResolverInterface $operationPathResolver, UrlGeneratorInterface $urlGenerator)
49+
public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceClassResolverInterface $resourceClassResolver, OperationMethodResolverInterface $operationMethodResolver, OperationPathResolverInterface $operationPathResolver, UrlGeneratorInterface $urlGenerator, FilterCollection $filterCollection = null)
4850
{
4951
$this->resourceMetadataFactory = $resourceMetadataFactory;
5052
$this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
@@ -53,6 +55,7 @@ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFa
5355
$this->operationMethodResolver = $operationMethodResolver;
5456
$this->operationPathResolver = $operationPathResolver;
5557
$this->urlGenerator = $urlGenerator;
58+
$this->filterCollection = $filterCollection;
5659
}
5760

5861
/**
@@ -196,6 +199,10 @@ private function updateGetOperation(\ArrayObject $pathOperation, array $mimeType
196199
],
197200
];
198201

202+
if (!isset($pathOperation['parameters']) && count($parameters = $this->getFiltersParameters($resourceClass, $operationName, $resourceMetadata)) > 0) {
203+
$pathOperation['parameters'] = $parameters;
204+
}
205+
199206
return $pathOperation;
200207
}
201208

@@ -421,7 +428,6 @@ private function getPropertySchema(PropertyMetadata $propertyMetadata) : \ArrayO
421428
* Gets the Swagger's type corresponding to the given PHP's type.
422429
*
423430
* @param string $type
424-
*
425431
* @param bool $isCollection
426432
* @param string $className
427433
* @param bool $readableLink
@@ -503,22 +509,45 @@ private function computeDoc(Documentation $documentation, \ArrayObject $definiti
503509
return $doc;
504510
}
505511

512+
/**
513+
* Gets Swagger parameters corresponding to enabled filters.
514+
*
515+
* @param string $resourceClass
516+
* @param string $operationName
517+
* @param ResourceMetadata $resourceMetadata
518+
*
519+
* @return array
520+
*/
506521
private function getFiltersParameters(string $resourceClass, string $operationName, ResourceMetadata $resourceMetadata) : array
507522
{
508-
$parameters = new \ArrayObject();
509-
foreach($resourceMetadata->getCollectionOperationAttribute($operationName, 'filters', [], true) as $filter) {
510-
foreach ($filter->getDescription($resourceClass) as $variable => $data) {
523+
if (null === $this->filterCollection) {
524+
return [];
525+
}
526+
527+
$parameters = [];
528+
$resourceFilters = $resourceMetadata->getCollectionOperationAttribute($operationName, 'filters', [], true);
529+
foreach ($this->filterCollection as $filterName => $filter) {
530+
if (!in_array($filterName, $resourceFilters)) {
531+
continue;
532+
}
533+
534+
foreach ($filter->getDescription($resourceClass) as $name => $data) {
511535
$parameter = [
512-
'name' => $variable,
536+
'name' => $name,
513537
'in' => 'query',
514538
'required' => $data['required'],
515-
'type' => $this->getType($data['type'])
516539
];
540+
$parameter += $this->getType($data['type'], false);
541+
542+
if (isset($data['swagger'])) {
543+
$parameter = $data['swagger'] + $parameter;
544+
}
517545

518-
$data['swagger'] ?? $parameter = $data['swagger'] + $parameter;
519546
$parameters[] = $parameter;
520547
}
521548
}
549+
550+
return $parameters;
522551
}
523552

524553
/**

tests/Fixtures/DummyFilter.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace ApiPlatform\Core\Tests\Fixtures;
13+
14+
use ApiPlatform\Core\Api\FilterInterface;
15+
16+
/**
17+
* @author Kévin Dunglas <[email protected]>
18+
*/
19+
class DummyFilter implements FilterInterface
20+
{
21+
private $description;
22+
23+
public function __construct(array $description)
24+
{
25+
$this->description = $description;
26+
}
27+
28+
/**
29+
* Gets the description of this filter for the given resource.
30+
*
31+
* Returns an array with the filter parameter names as keys and array with the following data as values:
32+
* - property: the property where the filter is applied
33+
* - type: the type of the filter
34+
* - required: if this filter is required
35+
* - strategy: the used strategy
36+
* The description can contain additional data specific to a filter.
37+
*
38+
* @param string $resourceClass
39+
*
40+
* @return array
41+
*/
42+
public function getDescription(string $resourceClass) : array
43+
{
44+
return $this->description;
45+
}
46+
}

0 commit comments

Comments
 (0)