Skip to content

Commit 4312a1f

Browse files
committedOct 4, 2024
fix(metadata): register parameters on graphql operations
1 parent b0d5a2a commit 4312a1f

File tree

4 files changed

+99
-58
lines changed

4 files changed

+99
-58
lines changed
 

‎src/GraphQl/Type/FieldsBuilder.php

+30-8
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
use ApiPlatform\GraphQl\Exception\InvalidTypeException;
1919
use ApiPlatform\GraphQl\Resolver\Factory\ResolverFactoryInterface;
2020
use ApiPlatform\GraphQl\Type\Definition\TypeInterface;
21+
use ApiPlatform\Metadata\FilterInterface;
2122
use ApiPlatform\Metadata\GraphQl\Mutation;
2223
use ApiPlatform\Metadata\GraphQl\Operation;
2324
use ApiPlatform\Metadata\GraphQl\Query;
2425
use ApiPlatform\Metadata\GraphQl\Subscription;
2526
use ApiPlatform\Metadata\InflectorInterface;
27+
use ApiPlatform\Metadata\OpenApiParameterFilterInterface;
2628
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2729
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2830
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
@@ -296,20 +298,40 @@ public function resolveResourceArgs(array $args, Operation $operation): array
296298
continue;
297299
}
298300

301+
$filter = $this->filterLocator->get($filterId);
299302
$parsedKey = explode('[:property]', $key);
300303
$flattenFields = [];
301-
foreach ($this->filterLocator->get($filterId)->getDescription($operation->getClass()) as $key => $value) {
302-
$values = [];
303-
parse_str($key, $values);
304-
if (isset($values[$parsedKey[0]])) {
305-
$values = $values[$parsedKey[0]];
304+
305+
if ($filter instanceof FilterInterface) {
306+
foreach ($filter->getDescription($operation->getClass()) as $name => $value) {
307+
$values = [];
308+
parse_str($name, $values);
309+
if (isset($values[$parsedKey[0]])) {
310+
$values = $values[$parsedKey[0]];
311+
}
312+
313+
$name = key($values);
314+
$flattenFields[] = ['name' => $name, 'required' => $value['required'] ?? null, 'description' => $value['description'] ?? null, 'leafs' => $values[$name], 'type' => $value['type'] ?? 'string'];
315+
}
316+
317+
$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0]);
318+
}
319+
320+
if ($filter instanceof OpenApiParameterFilterInterface) {
321+
foreach ($filter->getOpenApiParameters($parameter) as $value) {
322+
$values = [];
323+
parse_str($value->getName(), $values);
324+
if (isset($values[$parsedKey[0]])) {
325+
$values = $values[$parsedKey[0]];
326+
}
327+
328+
$name = key($values);
329+
$flattenFields[] = ['name' => $name, 'required' => $value->getRequired(), 'description' => $value->getDescription(), 'leafs' => $values[$name], 'type' => $value->getSchema()['type'] ?? 'string'];
306330
}
307331

308-
$name = key($values);
309-
$flattenFields[] = ['name' => $name, 'required' => $value['required'] ?? null, 'description' => $value['description'] ?? null, 'leafs' => $values[$name], 'type' => $value['type'] ?? 'string'];
332+
$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0].$operation->getShortName().$operation->getName());
310333
}
311334

312-
$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0]);
313335
continue;
314336
}
315337

‎src/Laravel/State/ParameterValidatorProvider.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(
4444

4545
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
4646
{
47-
if (!($request = $context['request']) instanceof Request) {
47+
if (!($request = $context['request'] ?? null) instanceof Request) {
4848
return $this->decorated->provide($operation, $uriVariables, $context);
4949
}
5050

‎src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php

+67-48
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use ApiPlatform\Metadata\FilterInterface;
1818
use ApiPlatform\Metadata\JsonSchemaFilterInterface;
1919
use ApiPlatform\Metadata\OpenApiParameterFilterInterface;
20+
use ApiPlatform\Metadata\Operation;
2021
use ApiPlatform\Metadata\Parameter;
2122
use ApiPlatform\Metadata\Parameters;
2223
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
@@ -34,6 +35,8 @@
3435
*/
3536
final class ParameterResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
3637
{
38+
private array $localPropertyCache;
39+
3740
public function __construct(
3841
private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory,
3942
private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory,
@@ -47,51 +50,12 @@ public function create(string $resourceClass): ResourceMetadataCollection
4750
{
4851
$resourceMetadataCollection = $this->decorated?->create($resourceClass) ?? new ResourceMetadataCollection($resourceClass);
4952

50-
$propertyNames = [];
51-
$properties = [];
52-
foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $i => $property) {
53-
$propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $property);
54-
if ($propertyMetadata->isReadable()) {
55-
$propertyNames[] = $property;
56-
$properties[$property] = $propertyMetadata;
57-
}
58-
}
59-
6053
foreach ($resourceMetadataCollection as $i => $resource) {
6154
$operations = $resource->getOperations();
6255

6356
$internalPriority = -1;
6457
foreach ($operations as $operationName => $operation) {
65-
$parameters = $operation->getParameters() ?? new Parameters();
66-
foreach ($parameters as $key => $parameter) {
67-
if (':property' === $key) {
68-
foreach ($propertyNames as $property) {
69-
$converted = $this->nameConverter?->denormalize($property) ?? $property;
70-
$propertyParameter = $this->setDefaults($converted, $parameter, $resourceClass, $properties);
71-
$priority = $propertyParameter->getPriority() ?? $internalPriority--;
72-
$parameters->add($converted, $propertyParameter->withPriority($priority)->withKey($converted));
73-
}
74-
75-
$parameters->remove($key, $parameter::class);
76-
continue;
77-
}
78-
79-
$key = $parameter->getKey() ?? $key;
80-
81-
if (str_contains($key, ':property')) {
82-
$p = [];
83-
foreach ($propertyNames as $prop) {
84-
$p[$this->nameConverter?->denormalize($prop) ?? $prop] = $prop;
85-
}
86-
87-
$parameter = $parameter->withExtraProperties(($parameter->getExtraProperties() ?? []) + ['_properties' => $p]);
88-
}
89-
90-
$parameter = $this->setDefaults($key, $parameter, $resourceClass, $properties);
91-
$priority = $parameter->getPriority() ?? $internalPriority--;
92-
$parameters->add($key, $parameter->withPriority($priority));
93-
}
94-
58+
$parameters = $this->getDefaultParameters($operation, $resourceClass, $internalPriority);
9559
if (\count($parameters) > 0) {
9660
$operations->add($operationName, $operation->withParameters($parameters));
9761
}
@@ -105,15 +69,10 @@ public function create(string $resourceClass): ResourceMetadataCollection
10569

10670
$internalPriority = -1;
10771
foreach ($graphQlOperations as $operationName => $operation) {
108-
$parameters = $operation->getParameters() ?? new Parameters();
109-
foreach ($operation->getParameters() ?? [] as $key => $parameter) {
110-
$key = $parameter->getKey() ?? $key;
111-
$parameter = $this->setDefaults($key, $parameter, $resourceClass, $properties);
112-
$priority = $parameter->getPriority() ?? $internalPriority--;
113-
$parameters->add($key, $parameter->withPriority($priority));
72+
$parameters = $this->getDefaultParameters($operation, $resourceClass, $internalPriority);
73+
if (\count($parameters) > 0) {
74+
$graphQlOperations[$operationName] = $operation->withParameters($parameters);
11475
}
115-
116-
$graphQlOperations[$operationName] = $operation->withParameters($parameters);
11776
}
11877

11978
$resourceMetadataCollection[$i] = $resource->withGraphQlOperations($graphQlOperations);
@@ -122,6 +81,66 @@ public function create(string $resourceClass): ResourceMetadataCollection
12281
return $resourceMetadataCollection;
12382
}
12483

84+
/**
85+
* @return array{propertyNames: string[], properties: array<string, ApiProperty>}
86+
*/
87+
private function getProperties(string $resourceClass): array
88+
{
89+
if (isset($this->localPropertyCache[$resourceClass])) {
90+
return $this->localPropertyCache[$resourceClass];
91+
}
92+
93+
$propertyNames = [];
94+
$properties = [];
95+
foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $property) {
96+
$propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $property);
97+
if ($propertyMetadata->isReadable()) {
98+
$propertyNames[] = $property;
99+
$properties[$property] = $propertyMetadata;
100+
}
101+
}
102+
103+
$this->localPropertyCache = [$resourceClass => ['propertyNames' => $propertyNames, 'properties' => $properties]];
104+
105+
return $this->localPropertyCache[$resourceClass];
106+
}
107+
108+
private function getDefaultParameters(Operation $operation, string $resourceClass, int &$internalPriority): Parameters
109+
{
110+
['propertyNames' => $propertyNames, 'properties' => $properties] = $this->getProperties($resourceClass);
111+
$parameters = $operation->getParameters() ?? new Parameters();
112+
foreach ($parameters as $key => $parameter) {
113+
if (':property' === $key) {
114+
foreach ($propertyNames as $property) {
115+
$converted = $this->nameConverter?->denormalize($property) ?? $property;
116+
$propertyParameter = $this->setDefaults($converted, $parameter, $resourceClass, $properties);
117+
$priority = $propertyParameter->getPriority() ?? $internalPriority--;
118+
$parameters->add($converted, $propertyParameter->withPriority($priority)->withKey($converted));
119+
}
120+
121+
$parameters->remove($key, $parameter::class);
122+
continue;
123+
}
124+
125+
$key = $parameter->getKey() ?? $key;
126+
127+
if (str_contains($key, ':property')) {
128+
$p = [];
129+
foreach ($propertyNames as $prop) {
130+
$p[$this->nameConverter?->denormalize($prop) ?? $prop] = $prop;
131+
}
132+
133+
$parameter = $parameter->withExtraProperties($parameter->getExtraProperties() + ['_properties' => $p]);
134+
}
135+
136+
$parameter = $this->setDefaults($key, $parameter, $resourceClass, $properties);
137+
$priority = $parameter->getPriority() ?? $internalPriority--;
138+
$parameters->add($key, $parameter->withPriority($priority));
139+
}
140+
141+
return $parameters;
142+
}
143+
125144
private function addFilterMetadata(Parameter $parameter): Parameter
126145
{
127146
if (!($filterId = $parameter->getFilter())) {

‎src/Symfony/Validator/State/ParameterValidatorProvider.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function __construct(
4040

4141
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
4242
{
43-
if (!($request = $context['request']) instanceof Request) {
43+
if (!($request = $context['request'] ?? null) instanceof Request) {
4444
return $this->decorated->provide($operation, $uriVariables, $context);
4545
}
4646

0 commit comments

Comments
 (0)
Please sign in to comment.