Skip to content

Commit 91e76e7

Browse files
committed
test(serializer): implement Parameter provider
1 parent 5232204 commit 91e76e7

File tree

7 files changed

+266
-1
lines changed

7 files changed

+266
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Serializer\Parameter;
15+
16+
use ApiPlatform\Metadata\Operation;
17+
use ApiPlatform\Metadata\Parameter;
18+
use ApiPlatform\Serializer\Filter\FilterInterface;
19+
use ApiPlatform\State\ParameterProviderInterface;
20+
use ApiPlatform\State\Util\RequestAttributesExtractor;
21+
use Psr\Container\ContainerInterface;
22+
23+
/**
24+
* @experimental
25+
*/
26+
final class SerializerFilterParameterProvider implements ParameterProviderInterface
27+
{
28+
public function __construct(private readonly ?ContainerInterface $filterLocator)
29+
{
30+
}
31+
32+
public function provide(Parameter $parameter, array $parameters = [], array $context = []): ?Operation
33+
{
34+
if (null === ($request = $context['request'] ?? null) || null === ($operation = $context['operation'] ?? null)) {
35+
return null;
36+
}
37+
38+
$filter = $parameter->getFilter();
39+
if (!\is_string($filter) || !$this->filterLocator->has($filter)) {
40+
return null;
41+
}
42+
43+
$filter = $this->filterLocator->get($filter);
44+
if (!$filter instanceof FilterInterface) {
45+
return null;
46+
}
47+
48+
$context = $operation->getNormalizationContext();
49+
$filter->apply($request, true, RequestAttributesExtractor::extractAttributes($request), $context);
50+
51+
return $operation->withNormalizationContext($context);
52+
}
53+
}

tests/Fixtures/TestBundle/ApiResource/Headers.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
output: false,
2323
operations: [
2424
new Get(uriTemplate: 'redirect_to_foobar'),
25-
]
25+
],
26+
graphQlOperations: []
2627
)]
2728
class Headers
2829
{
30+
public $id;
2931
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource;
15+
16+
use ApiPlatform\Metadata\Get;
17+
use ApiPlatform\Metadata\GetCollection;
18+
use ApiPlatform\Metadata\HeaderParameter;
19+
use ApiPlatform\Metadata\Link;
20+
use ApiPlatform\Metadata\Parameter;
21+
use ApiPlatform\Metadata\QueryParameter;
22+
use ApiPlatform\Serializer\Filter\GroupFilter;
23+
use ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider;
24+
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
25+
use Symfony\Component\Serializer\Attribute\Groups;
26+
27+
#[Get(
28+
uriTemplate: 'with_parameters/{id}{._format}',
29+
uriVariables: [
30+
'id' => new Link(schema: ['type' => 'uuid'], property: 'id'),
31+
],
32+
parameters: [
33+
'groups' => new QueryParameter(filter: new GroupFilter(parameterName: 'groups', overrideDefaultGroups: false)),
34+
'group' => new QueryParameter(provider: [self::class, 'provideGroup']),
35+
'properties' => new QueryParameter(filter: 'my_dummy.property'),
36+
'service' => new QueryParameter(provider: CustomGroupParameterProvider::class),
37+
'auth' => new HeaderParameter(provider: [self::class, 'restrictAccess']),
38+
'priority' => new QueryParameter(provider: [self::class, 'assertSecond'], priority: 10),
39+
'priorityb' => new QueryParameter(provider: [self::class, 'assertFirst'], priority: 20),
40+
'array' => new QueryParameter(provider: [self::class, 'assertArray']),
41+
],
42+
provider: [self::class, 'provide']
43+
)]
44+
#[GetCollection(
45+
uriTemplate: 'with_parameters_collection',
46+
parameters: [
47+
'hydra' => new QueryParameter(property: 'a', required: true),
48+
],
49+
provider: [self::class, 'collectionProvider']
50+
)]
51+
#[QueryParameter(key: 'everywhere')]
52+
class WithParameter
53+
{
54+
protected static int $counter = 1;
55+
public int $id = 1;
56+
57+
#[Groups(['a'])]
58+
public $a = 'foo';
59+
#[Groups(['b', 'custom'])]
60+
public $b = 'bar';
61+
62+
public static function collectionProvider()
63+
{
64+
return [new self()];
65+
}
66+
67+
public static function provide()
68+
{
69+
return new self();
70+
}
71+
72+
public static function assertArray(): void
73+
{
74+
}
75+
76+
public static function assertFirst(): void
77+
{
78+
\assert(1 === static::$counter);
79+
++static::$counter;
80+
}
81+
82+
public static function assertSecond(): void
83+
{
84+
\assert(2 === static::$counter);
85+
}
86+
87+
public static function provideGroup(Parameter $parameter, array $parameters = [], array $context = [])
88+
{
89+
$operation = $context['operation'];
90+
91+
return $operation->withNormalizationContext(['groups' => $parameters['group']]);
92+
}
93+
94+
public static function restrictAccess(): void
95+
{
96+
throw new AccessDeniedHttpException();
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Parameter;
15+
16+
use ApiPlatform\Metadata\HttpOperation;
17+
use ApiPlatform\Metadata\Parameter;
18+
use ApiPlatform\State\ParameterProviderInterface;
19+
20+
final class CustomGroupParameterProvider implements ParameterProviderInterface
21+
{
22+
public function provide(Parameter $parameter, array $parameters = [], array $context = []): ?HttpOperation
23+
{
24+
return $context['operation']->withNormalizationContext(['groups' => 'custom']);
25+
}
26+
}

tests/Fixtures/app/config/config_common.yml

+5
Original file line numberDiff line numberDiff line change
@@ -445,3 +445,8 @@ services:
445445
api_platform.http_cache.tag_collector:
446446
class: ApiPlatform\Tests\Fixtures\TestBundle\HttpCache\TagCollectorDefault
447447
public: true
448+
449+
ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider:
450+
tags:
451+
- name: 'api_platform.parameter_provider'
452+
key: 'ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider'
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Functional\Parameters;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
18+
final class HydraTests extends ApiTestCase
19+
{
20+
public function testHydraTemplate(): void
21+
{
22+
$response = self::createClient()->request('GET', 'with_parameters_collection');
23+
$this->assertArraySubset(['hydra:search' => [
24+
'hydra:template' => '/with_parameters_collection{?hydra}',
25+
'hydra:mapping' => [
26+
['@type' => 'IriTemplateMapping', 'variable' => 'hydra', 'property' => 'a', 'required' => true],
27+
],
28+
]], $response->toArray());
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Functional\Parameters;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
18+
final class ParameterTests extends ApiTestCase
19+
{
20+
public function testWithGroupFilter(): void
21+
{
22+
$response = self::createClient()->request('GET', 'with_parameters/1?groups[]=b');
23+
$this->assertArraySubset(['b' => 'bar'], $response->toArray());
24+
$response = self::createClient()->request('GET', 'with_parameters/1?groups[]=b&groups[]=a');
25+
$this->assertArraySubset(['a' => 'foo', 'b' => 'bar'], $response->toArray());
26+
}
27+
28+
public function testWithGroupProvider(): void
29+
{
30+
$response = self::createClient()->request('GET', 'with_parameters/1?group[]=b&group[]=a');
31+
$this->assertArraySubset(['a' => 'foo', 'b' => 'bar'], $response->toArray());
32+
}
33+
34+
public function testWithServiceFilter(): void
35+
{
36+
$response = self::createClient()->request('GET', 'with_parameters/1?properties[]=a');
37+
$this->assertArraySubset(['a' => 'foo'], $response->toArray());
38+
}
39+
40+
public function testWithServiceProvider(): void
41+
{
42+
$response = self::createClient()->request('GET', 'with_parameters/1?service=blabla');
43+
$this->assertArrayNotHasKey('a', $response->toArray());
44+
}
45+
46+
public function testWithHeader(): void
47+
{
48+
self::createClient()->request('GET', 'with_parameters/1?service=blabla', ['headers' => ['auth' => 'foo']]);
49+
$this->assertResponseStatusCodeSame(403);
50+
}
51+
}

0 commit comments

Comments
 (0)