Skip to content

Commit 4171d5f

Browse files
authoredOct 15, 2024··
fix(graphql): register query parameter arguments with filters (#6726)
1 parent 48ab538 commit 4171d5f

File tree

3 files changed

+99
-60
lines changed

3 files changed

+99
-60
lines changed
 

‎src/GraphQl/Type/FieldsBuilder.php

+69-60
Original file line numberDiff line numberDiff line change
@@ -287,61 +287,6 @@ public function resolveResourceArgs(array $args, Operation $operation): array
287287
$args[$id]['type'] = $this->typeConverter->resolveType($arg['type']);
288288
}
289289

290-
/*
291-
* This is @experimental, read the comment on the parameterToObjectType function as additional information.
292-
*/
293-
foreach ($operation->getParameters() ?? [] as $parameter) {
294-
$key = $parameter->getKey();
295-
296-
if (str_contains($key, ':property')) {
297-
if (!($filterId = $parameter->getFilter()) || !$this->filterLocator->has($filterId)) {
298-
continue;
299-
}
300-
301-
$filter = $this->filterLocator->get($filterId);
302-
$parsedKey = explode('[:property]', $key);
303-
$flattenFields = [];
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'];
330-
}
331-
332-
$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0].$operation->getShortName().$operation->getName());
333-
}
334-
335-
continue;
336-
}
337-
338-
$args[$key] = ['type' => GraphQLType::string()];
339-
340-
if ($parameter->getRequired()) {
341-
$args[$key]['type'] = GraphQLType::nonNull($args[$key]['type']);
342-
}
343-
}
344-
345290
return $args;
346291
}
347292

@@ -463,12 +408,15 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
463408

464409
$args = [];
465410

466-
if (!$input && !$rootOperation instanceof Mutation && !$rootOperation instanceof Subscription && !$isStandardGraphqlType && $isCollectionType) {
467-
if (!$this->isEnumClass($resourceClass) && $this->pagination->isGraphQlEnabled($resourceOperation)) {
468-
$args = $this->getGraphQlPaginationArgs($resourceOperation);
469-
}
411+
if (!$input && !$rootOperation instanceof Mutation && !$rootOperation instanceof Subscription && !$isStandardGraphqlType) {
412+
if ($isCollectionType) {
413+
if (!$this->isEnumClass($resourceClass) && $this->pagination->isGraphQlEnabled($resourceOperation)) {
414+
$args = $this->getGraphQlPaginationArgs($resourceOperation);
415+
}
470416

471-
$args = $this->getFilterArgs($args, $resourceClass, $rootResource, $resourceOperation, $rootOperation, $property, $depth);
417+
$args = $this->getFilterArgs($args, $resourceClass, $rootResource, $resourceOperation, $rootOperation, $property, $depth);
418+
$args = $this->getParameterArgs($rootOperation, $args);
419+
}
472420
}
473421

474422
if ($isStandardGraphqlType || $input) {
@@ -491,6 +439,67 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
491439
return null;
492440
}
493441

442+
/*
443+
* This function is @experimental, read the comment on the parameterToObjectType function for additional information.
444+
* @experimental
445+
*/
446+
private function getParameterArgs(Operation $operation, array $args = []): array
447+
{
448+
foreach ($operation->getParameters() ?? [] as $parameter) {
449+
$key = $parameter->getKey();
450+
451+
if (!str_contains($key, ':property')) {
452+
$args[$key] = ['type' => GraphQLType::string()];
453+
454+
if ($parameter->getRequired()) {
455+
$args[$key]['type'] = GraphQLType::nonNull($args[$key]['type']);
456+
}
457+
458+
continue;
459+
}
460+
461+
if (!($filterId = $parameter->getFilter()) || !$this->filterLocator->has($filterId)) {
462+
continue;
463+
}
464+
465+
$filter = $this->filterLocator->get($filterId);
466+
$parsedKey = explode('[:property]', $key);
467+
$flattenFields = [];
468+
469+
if ($filter instanceof FilterInterface) {
470+
foreach ($filter->getDescription($operation->getClass()) as $name => $value) {
471+
$values = [];
472+
parse_str($name, $values);
473+
if (isset($values[$parsedKey[0]])) {
474+
$values = $values[$parsedKey[0]];
475+
}
476+
477+
$name = key($values);
478+
$flattenFields[] = ['name' => $name, 'required' => $value['required'] ?? null, 'description' => $value['description'] ?? null, 'leafs' => $values[$name], 'type' => $value['type'] ?? 'string'];
479+
}
480+
481+
$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0]);
482+
}
483+
484+
if ($filter instanceof OpenApiParameterFilterInterface) {
485+
foreach ($filter->getOpenApiParameters($parameter) as $value) {
486+
$values = [];
487+
parse_str($value->getName(), $values);
488+
if (isset($values[$parsedKey[0]])) {
489+
$values = $values[$parsedKey[0]];
490+
}
491+
492+
$name = key($values);
493+
$flattenFields[] = ['name' => $name, 'required' => $value->getRequired(), 'description' => $value->getDescription(), 'leafs' => $values[$name], 'type' => $value->getSchema()['type'] ?? 'string'];
494+
}
495+
496+
$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0].$operation->getShortName().$operation->getName());
497+
}
498+
}
499+
500+
return $args;
501+
}
502+
494503
private function getGraphQlPaginationArgs(Operation $queryOperation): array
495504
{
496505
$paginationType = $this->pagination->getGraphQlPaginationType($queryOperation);

‎src/Laravel/Tests/GraphQlTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,23 @@ public function testGetBooks(): void
4747
$this->assertArrayHasKey('data', $data);
4848
$this->assertArrayNotHasKey('errors', $data);
4949
}
50+
51+
public function testGetBooksWithPaginationAndOrder(): void
52+
{
53+
BookFactory::new()->has(AuthorFactory::new())->count(10)->create();
54+
$response = $this->postJson('/api/graphql', ['query' => '{
55+
books(first: 3, order: {name: "desc"}) {
56+
edges {
57+
node {
58+
id, name, publicationDate, author { id, name }
59+
}
60+
}
61+
}
62+
}'], ['accept' => ['application/json']]);
63+
$response->assertStatus(200);
64+
$data = $response->json();
65+
$this->assertArrayHasKey('data', $data);
66+
$this->assertCount(3, $data['data']['books']['edges']);
67+
$this->assertArrayNotHasKey('errors', $data);
68+
}
5069
}

‎src/Laravel/workbench/app/Models/Book.php

+11
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515

1616
use ApiPlatform\Laravel\Eloquent\Filter\DateFilter;
1717
use ApiPlatform\Laravel\Eloquent\Filter\EqualsFilter;
18+
use ApiPlatform\Laravel\Eloquent\Filter\OrderFilter;
1819
use ApiPlatform\Laravel\Eloquent\Filter\OrFilter;
1920
use ApiPlatform\Laravel\Eloquent\Filter\PartialSearchFilter;
2021
use ApiPlatform\Laravel\Eloquent\Filter\RangeFilter;
2122
use ApiPlatform\Metadata\ApiResource;
2223
use ApiPlatform\Metadata\Delete;
2324
use ApiPlatform\Metadata\Get;
2425
use ApiPlatform\Metadata\GetCollection;
26+
use ApiPlatform\Metadata\GraphQl\Query;
27+
use ApiPlatform\Metadata\GraphQl\QueryCollection;
2528
use ApiPlatform\Metadata\Patch;
2629
use ApiPlatform\Metadata\Post;
2730
use ApiPlatform\Metadata\Put;
@@ -44,6 +47,14 @@
4447
new Post(),
4548
new Delete(),
4649
new GetCollection(),
50+
],
51+
graphQlOperations: [
52+
new Query(),
53+
new QueryCollection(
54+
parameters: [
55+
new QueryParameter(key: 'order[:property]', filter: OrderFilter::class),
56+
],
57+
),
4758
]
4859
)]
4960
#[QueryParameter(key: 'isbn', filter: PartialSearchFilter::class, constraints: 'min:2')]

0 commit comments

Comments
 (0)
Please sign in to comment.