Skip to content

Commit a2c48a9

Browse files
committed
fix(metadata): try to improve handling of stateOptions
1 parent 99262dc commit a2c48a9

File tree

6 files changed

+448
-7
lines changed

6 files changed

+448
-7
lines changed

src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
2323
use ApiPlatform\OpenApi\Model\Parameter as OpenApiParameter;
2424
use ApiPlatform\Serializer\Filter\FilterInterface as SerializerFilterInterface;
25+
use ApiPlatform\State\OptionsInterface;
2526
use Psr\Container\ContainerInterface;
2627
use Symfony\Component\Validator\Constraints\Choice;
2728
use Symfony\Component\Validator\Constraints\Count;
@@ -61,7 +62,8 @@ public function create(string $resourceClass): ResourceMetadataCollection
6162
$parameters = $operation->getParameters() ?? new Parameters();
6263
foreach ($parameters as $key => $parameter) {
6364
$key = $parameter->getKey() ?? $key;
64-
$parameter = $this->setDefaults($key, $parameter, $resourceClass);
65+
$stateOptions = $resource->getStateOptions();
66+
$parameter = $this->setDefaults($key, $parameter, $resourceClass, $stateOptions);
6567
$priority = $parameter->getPriority() ?? $internalPriority--;
6668
$parameters->add($key, $parameter->withPriority($priority));
6769
}
@@ -87,7 +89,8 @@ public function create(string $resourceClass): ResourceMetadataCollection
8789
$parameters = $operation->getParameters() ?? new Parameters();
8890
foreach ($operation->getParameters() ?? [] as $key => $parameter) {
8991
$key = $parameter->getKey() ?? $key;
90-
$parameter = $this->setDefaults($key, $parameter, $resourceClass);
92+
$stateOptions = $resource->getStateOptions();
93+
$parameter = $this->setDefaults($key, $parameter, $resourceClass, $stateOptions);
9194
$priority = $parameter->getPriority() ?? $internalPriority--;
9295
$parameters->add($key, $parameter->withPriority($priority));
9396
}
@@ -101,7 +104,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
101104
return $resourceMetadataCollection;
102105
}
103106

104-
private function setDefaults(string $key, Parameter $parameter, string $resourceClass): Parameter
107+
private function setDefaults(string $key, Parameter $parameter, string $resourceClass, ?OptionsInterface $stateOptions): Parameter
105108
{
106109
if (null === $parameter->getKey()) {
107110
$parameter = $parameter->withKey($key);
@@ -116,8 +119,8 @@ private function setDefaults(string $key, Parameter $parameter, string $resource
116119
$parameter = $parameter->withProvider('api_platform.serializer.filter_parameter_provider');
117120
}
118121

119-
// Read filter description to populate the Parameter
120-
$description = $filter instanceof FilterInterface ? $filter->getDescription($resourceClass) : [];
122+
$description = $this->getDescription($stateOptions, $filter, $resourceClass);
123+
121124
if (($schema = $description[$key]['schema'] ?? null) && null === $parameter->getSchema()) {
122125
$parameter = $parameter->withSchema($schema);
123126
}
@@ -242,7 +245,7 @@ private function addFilterValidation(HttpOperation $operation): Parameters
242245
}
243246

244247
$filter = $this->filterLocator->get($filter);
245-
foreach ($filter->getDescription($operation->getClass()) as $parameterName => $definition) {
248+
foreach ($this->getDescription($operation->getStateOptions(), $filter, $operation->getClass()) as $parameterName => $definition) {
246249
$key = $parameterName;
247250
$required = $definition['required'] ?? false;
248251
$schema = $definition['schema'] ?? null;
@@ -286,7 +289,7 @@ private function addFilterValidation(HttpOperation $operation): Parameters
286289

287290
$parameters->add($key, $this->addSchemaValidation(
288291
// we disable openapi and hydra on purpose as their docs comes from filters see the condition for addFilterValidation above
289-
new QueryParameter(key: $key, property: $definition['property'] ?? null, priority: $internalPriority--, schema: $schema, openApi: false, hydra: false),
292+
new QueryParameter(key: $key, schema: $schema, openApi: false, property: $definition['property'] ?? null, priority: $internalPriority--, hydra: false),
290293
$schema,
291294
$required,
292295
$openApi
@@ -296,4 +299,17 @@ private function addFilterValidation(HttpOperation $operation): Parameters
296299

297300
return $parameters;
298301
}
302+
303+
private function getDescription(?OptionsInterface $stateOptions, ?FilterInterface $filter, string $resourceClass): array
304+
{
305+
if ($stateOptions instanceof OptionsInterface) {
306+
return $filter->getDescription($stateOptions->getEntityClass());
307+
}
308+
309+
if ($filter instanceof FilterInterface) {
310+
return $filter->getDescription($resourceClass);
311+
}
312+
313+
return [];
314+
}
299315
}

src/State/OptionsInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313

1414
namespace ApiPlatform\State;
1515

16+
/**
17+
* Interface for state options used in API Platform.
18+
*
19+
* @method string getEntityClass() Gets the fully qualified class name of the entity associated with the state options.
20+
*/
1621
interface OptionsInterface
1722
{
1823
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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\Doctrine\Orm\Filter\DateFilter;
17+
use ApiPlatform\Doctrine\Orm\State\Options;
18+
use ApiPlatform\Metadata\ApiFilter;
19+
use ApiPlatform\Metadata\ApiResource;
20+
use ApiPlatform\Metadata\GetCollection;
21+
use ApiPlatform\Metadata\QueryParameter;
22+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Agent;
23+
use Symfony\Component\Serializer\Attribute\Groups;
24+
25+
#[ApiFilter(DateFilter::class, properties: ['birthday'], alias: 'app_filter_date')]
26+
#[ApiResource(
27+
shortName: 'Agent',
28+
operations: [
29+
new GetCollection(parameters: [
30+
'bla[:property]' => new QueryParameter(filter: 'app_filter_date'),
31+
]),
32+
],
33+
stateOptions: new Options(entityClass: Agent::class)
34+
)]
35+
#[ApiFilter(DateFilter::class, properties: ['birthday'])]
36+
#[ApiResource(
37+
shortName: 'AgentSimple',
38+
operations: [
39+
new GetCollection(),
40+
],
41+
stateOptions: new Options(entityClass: Agent::class)
42+
)]
43+
class AgentApi
44+
{
45+
#[Groups(['agent:read'])]
46+
private ?int $id = null;
47+
48+
#[Groups(['agent:read', 'agent:write'])]
49+
private ?string $name = null;
50+
51+
#[Groups(['agent:read', 'agent:write'])]
52+
private ?\DateTimeInterface $birthday = null;
53+
54+
public function getId(): ?int
55+
{
56+
return $this->id;
57+
}
58+
59+
public function setId(?int $id): self
60+
{
61+
$this->id = $id;
62+
63+
return $this;
64+
}
65+
66+
public function getName(): ?string
67+
{
68+
return $this->name;
69+
}
70+
71+
public function setName(?string $name): self
72+
{
73+
$this->name = $name;
74+
75+
return $this;
76+
}
77+
78+
public function getBirthday(): ?\DateTimeInterface
79+
{
80+
return $this->birthday;
81+
}
82+
83+
public function setBirthday(?\DateTimeInterface $birthday): self
84+
{
85+
$this->birthday = $birthday;
86+
87+
return $this;
88+
}
89+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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\Document;
15+
16+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
17+
18+
#[ODM\Document]
19+
class AgentDocument
20+
{
21+
#[ODM\Id(strategy: 'INCREMENT', type: 'int')]
22+
public ?int $id = null;
23+
24+
#[ODM\Field]
25+
public ?string $name = null;
26+
27+
#[ODM\Field]
28+
public ?string $apiKey = null;
29+
30+
#[ODM\Field]
31+
public ?\DateTimeImmutable $createdAt = null;
32+
33+
#[ODM\Field]
34+
public ?\DateTimeImmutable $birthday = null;
35+
36+
public function getId(): ?int
37+
{
38+
return $this->id;
39+
}
40+
41+
public function setId(int $id): static
42+
{
43+
$this->id = $id;
44+
45+
return $this;
46+
}
47+
48+
public function getName(): ?string
49+
{
50+
return $this->name;
51+
}
52+
53+
public function setName(string $name): static
54+
{
55+
$this->name = $name;
56+
57+
return $this;
58+
}
59+
60+
public function getApiKey(): ?string
61+
{
62+
return $this->apiKey;
63+
}
64+
65+
public function setApiKey(string $apiKey): static
66+
{
67+
$this->apiKey = $apiKey;
68+
69+
return $this;
70+
}
71+
72+
public function getCreatedAt(): ?\DateTimeImmutable
73+
{
74+
return $this->createdAt;
75+
}
76+
77+
public function setCreatedAt(\DateTimeImmutable $createdAt): static
78+
{
79+
$this->createdAt = $createdAt;
80+
81+
return $this;
82+
}
83+
84+
public function getBirthday(): ?\DateTimeImmutable
85+
{
86+
return $this->birthday;
87+
}
88+
89+
public function setBirthday(\DateTimeImmutable $birthday): static
90+
{
91+
$this->birthday = $birthday;
92+
93+
return $this;
94+
}
95+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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\Entity;
15+
16+
use Doctrine\ORM\Mapping as ORM;
17+
18+
#[ORM\Entity]
19+
class Agent
20+
{
21+
#[ORM\Id]
22+
#[ORM\GeneratedValue]
23+
#[ORM\Column]
24+
public ?int $id = null;
25+
26+
#[ORM\Column(length: 255)]
27+
public ?string $name = null;
28+
29+
#[ORM\Column(length: 255)]
30+
public ?string $apiKey = null;
31+
32+
#[ORM\Column]
33+
public ?\DateTimeImmutable $createdAt = null;
34+
35+
#[ORM\Column]
36+
public ?\DateTimeImmutable $birthday = null;
37+
38+
public function getId(): ?int
39+
{
40+
return $this->id;
41+
}
42+
43+
public function setId(int $id): static
44+
{
45+
$this->id = $id;
46+
47+
return $this;
48+
}
49+
50+
public function getName(): ?string
51+
{
52+
return $this->name;
53+
}
54+
55+
public function setName(string $name): static
56+
{
57+
$this->name = $name;
58+
59+
return $this;
60+
}
61+
62+
public function getApiKey(): ?string
63+
{
64+
return $this->apiKey;
65+
}
66+
67+
public function setApiKey(string $apiKey): static
68+
{
69+
$this->apiKey = $apiKey;
70+
71+
return $this;
72+
}
73+
74+
public function getCreatedAt(): ?\DateTimeImmutable
75+
{
76+
return $this->createdAt;
77+
}
78+
79+
public function setCreatedAt(\DateTimeImmutable $createdAt): static
80+
{
81+
$this->createdAt = $createdAt;
82+
83+
return $this;
84+
}
85+
86+
public function getBirthday(): ?\DateTimeImmutable
87+
{
88+
return $this->birthday;
89+
}
90+
91+
public function setBirthday(\DateTimeImmutable $birthday): static
92+
{
93+
$this->birthday = $birthday;
94+
95+
return $this;
96+
}
97+
}

0 commit comments

Comments
 (0)