Skip to content

Commit c1cb3cd

Browse files
authored
Revert "fix(graphql): use right nested operation (#5102)" (#5111)
This reverts commit 44337dd.
1 parent 44337dd commit c1cb3cd

25 files changed

+115
-446
lines changed

features/graphql/collection.feature

-46
Original file line numberDiff line numberDiff line change
@@ -910,49 +910,3 @@ Feature: GraphQL collection support
910910
Then the response status code should be 200
911911
And the response should be in JSON
912912
And the JSON node "data.fooDummies.collection" should have 1 element
913-
914-
@createSchema
915-
Scenario: Retrieve paginated collections using mixed pagination
916-
Given there are 5 fooDummy objects with fake names
917-
When I send the following GraphQL request:
918-
"""
919-
{
920-
fooDummies(page: 1) {
921-
collection {
922-
id
923-
name
924-
soManies(first: 2) {
925-
edges {
926-
node {
927-
content
928-
}
929-
cursor
930-
}
931-
pageInfo {
932-
startCursor
933-
endCursor
934-
hasNextPage
935-
hasPreviousPage
936-
}
937-
}
938-
}
939-
paginationInfo {
940-
itemsPerPage
941-
lastPage
942-
totalCount
943-
}
944-
}
945-
}
946-
"""
947-
Then the response status code should be 200
948-
And the response should be in JSON
949-
And the JSON node "data.fooDummies.collection" should have 3 elements
950-
And the JSON node "data.fooDummies.collection[2].id" should exist
951-
And the JSON node "data.fooDummies.collection[2].name" should exist
952-
And the JSON node "data.fooDummies.collection[2].soManies" should exist
953-
And the JSON node "data.fooDummies.collection[2].soManies.edges" should have 2 elements
954-
And the JSON node "data.fooDummies.collection[2].soManies.edges[1].node.content" should be equal to "So many 1"
955-
And the JSON node "data.fooDummies.collection[2].soManies.pageInfo.startCursor" should be equal to "MA=="
956-
And the JSON node "data.fooDummies.paginationInfo.itemsPerPage" should be equal to the number 3
957-
And the JSON node "data.fooDummies.paginationInfo.lastPage" should be equal to the number 2
958-
And the JSON node "data.fooDummies.paginationInfo.totalCount" should be equal to the number 5

features/main/default_order.feature

+5-31
Original file line numberDiff line numberDiff line change
@@ -79,61 +79,35 @@ Feature: Default order
7979
"@type": "FooDummy",
8080
"id": 5,
8181
"name": "Balbo",
82-
"dummy": "/dummies/5",
83-
"soManies": [
84-
"/so_manies/13",
85-
"/so_manies/14",
86-
"/so_manies/15"
87-
]
88-
82+
"dummy": "/dummies/5"
8983
},
9084
{
9185
"@id": "/foo_dummies/3",
9286
"@type": "FooDummy",
9387
"id": 3,
9488
"name": "Sthenelus",
95-
"dummy": "/dummies/3",
96-
"soManies": [
97-
"/so_manies/7",
98-
"/so_manies/8",
99-
"/so_manies/9"
100-
]
89+
"dummy": "/dummies/3"
10190
},
10291
{
10392
"@id": "/foo_dummies/2",
10493
"@type": "FooDummy",
10594
"id": 2,
10695
"name": "Ephesian",
107-
"dummy": "/dummies/2",
108-
"soManies": [
109-
"/so_manies/4",
110-
"/so_manies/5",
111-
"/so_manies/6"
112-
]
96+
"dummy": "/dummies/2"
11397
},
11498
{
11599
"@id": "/foo_dummies/1",
116100
"@type": "FooDummy",
117101
"id": 1,
118102
"name": "Hawsepipe",
119-
"dummy": "/dummies/1",
120-
"soManies": [
121-
"/so_manies/1",
122-
"/so_manies/2",
123-
"/so_manies/3"
124-
]
103+
"dummy": "/dummies/1"
125104
},
126105
{
127106
"@id": "/foo_dummies/4",
128107
"@type": "FooDummy",
129108
"id": 4,
130109
"name": "Separativeness",
131-
"dummy": "/dummies/4",
132-
"soManies": [
133-
"/so_manies/10",
134-
"/so_manies/11",
135-
"/so_manies/12"
136-
]
110+
"dummy": "/dummies/4"
137111
}
138112
],
139113
"hydra:totalItems": 5,

src/GraphQl/Type/FieldsBuilder.php

+40-35
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
use ApiPlatform\Exception\OperationNotFoundException;
1818
use ApiPlatform\GraphQl\Resolver\Factory\ResolverFactoryInterface;
1919
use ApiPlatform\GraphQl\Type\Definition\TypeInterface;
20-
use ApiPlatform\Metadata\Extractor\DynamicResourceExtractorInterface;
2120
use ApiPlatform\Metadata\GraphQl\Mutation;
2221
use ApiPlatform\Metadata\GraphQl\Operation;
22+
use ApiPlatform\Metadata\GraphQl\Query;
23+
use ApiPlatform\Metadata\GraphQl\QueryCollection;
2324
use ApiPlatform\Metadata\GraphQl\Subscription;
25+
use ApiPlatform\Metadata\Operation as AbstractOperation;
2426
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2527
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2628
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
@@ -45,7 +47,7 @@
4547
*/
4648
final class FieldsBuilder implements FieldsBuilderInterface
4749
{
48-
public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly DynamicResourceExtractorInterface $dynamicResourceExtractor, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly TypesContainerInterface $typesContainer, private readonly TypeBuilderInterface $typeBuilder, private readonly TypeConverterInterface $typeConverter, private readonly ResolverFactoryInterface $itemResolverFactory, private readonly ResolverFactoryInterface $collectionResolverFactory, private readonly ResolverFactoryInterface $itemMutationResolverFactory, private readonly ResolverFactoryInterface $itemSubscriptionResolverFactory, private readonly ContainerInterface $filterLocator, private readonly Pagination $pagination, private readonly ?NameConverterInterface $nameConverter, private readonly string $nestingSeparator)
50+
public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly TypesContainerInterface $typesContainer, private readonly TypeBuilderInterface $typeBuilder, private readonly TypeConverterInterface $typeConverter, private readonly ResolverFactoryInterface $itemResolverFactory, private readonly ResolverFactoryInterface $collectionResolverFactory, private readonly ResolverFactoryInterface $itemMutationResolverFactory, private readonly ResolverFactoryInterface $itemSubscriptionResolverFactory, private readonly ContainerInterface $filterLocator, private readonly Pagination $pagination, private readonly ?NameConverterInterface $nameConverter, private readonly string $nestingSeparator)
4951
{
5052
}
5153

@@ -254,25 +256,7 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
254256
$resourceClass = $type->getClassName();
255257
}
256258

257-
$resourceOperation = $rootOperation;
258-
if ($resourceClass && $rootOperation->getClass() && $this->resourceClassResolver->isResourceClass($resourceClass) && $rootOperation->getClass() !== $resourceClass) {
259-
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass);
260-
try {
261-
$resourceOperation = $resourceMetadataCollection->getOperation($isCollectionType ? 'collection_query' : 'item_query');
262-
} catch (OperationNotFoundException) {
263-
// If there is no query operation for a nested resource, use a dynamic resource to get one.
264-
$dynamicResourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($this->dynamicResourceExtractor->addResource($resourceClass));
265-
266-
$resourceOperation = $dynamicResourceMetadataCollection->getOperation($isCollectionType ? 'collection_query' : 'item_query')
267-
->withResource($resourceMetadataCollection[0]);
268-
}
269-
}
270-
271-
if (!$resourceOperation instanceof Operation) {
272-
throw new \LogicException('The resource operation should be a GraphQL operation.');
273-
}
274-
275-
$graphqlType = $this->convertType($type, $input, $resourceOperation, $rootOperation, $resourceClass ?? '', $rootResource, $property, $depth, $forceNullable);
259+
$graphqlType = $this->convertType($type, $input, $rootOperation, $resourceClass ?? '', $rootResource, $property, $depth, $forceNullable);
276260

277261
$graphqlWrappedType = $graphqlType instanceof WrappingType ? $graphqlType->getWrappedType(true) : $graphqlType;
278262
$isStandardGraphqlType = \in_array($graphqlWrappedType, GraphQLType::getStandardTypes(), true);
@@ -287,22 +271,43 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
287271

288272
$args = [];
289273

274+
$resolverOperation = $rootOperation;
275+
276+
if ($resourceClass && $this->resourceClassResolver->isResourceClass($resourceClass) && $rootOperation->getClass() !== $resourceClass) {
277+
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass);
278+
$resolverOperation = $resourceMetadataCollection->getOperation(null, $isCollectionType);
279+
280+
if (!$resolverOperation instanceof Operation) {
281+
$resolverOperation = ($isCollectionType ? new QueryCollection() : new Query())->withOperation($resolverOperation);
282+
}
283+
}
284+
290285
if (!$input && !$rootOperation instanceof Mutation && !$rootOperation instanceof Subscription && !$isStandardGraphqlType && $isCollectionType) {
291-
if ($this->pagination->isGraphQlEnabled($resourceOperation)) {
292-
$args = $this->getGraphQlPaginationArgs($resourceOperation);
286+
if ($this->pagination->isGraphQlEnabled($rootOperation)) {
287+
$args = $this->getGraphQlPaginationArgs($rootOperation);
288+
}
289+
290+
// Find the collection operation to get filters, there might be a smarter way to do this
291+
$operation = null;
292+
if (!empty($resourceClass)) {
293+
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass);
294+
try {
295+
$operation = $resourceMetadataCollection->getOperation(null, true);
296+
} catch (OperationNotFoundException) {
297+
}
293298
}
294299

295-
$args = $this->getFilterArgs($args, $resourceClass, $rootResource, $resourceOperation, $rootOperation, $property, $depth);
300+
$args = $this->getFilterArgs($args, $resourceClass, $rootResource, $rootOperation, $property, $depth, $operation);
296301
}
297302

298303
if ($isStandardGraphqlType || $input) {
299304
$resolve = null;
300305
} elseif (($rootOperation instanceof Mutation || $rootOperation instanceof Subscription) && $depth <= 0) {
301-
$resolve = $rootOperation instanceof Mutation ? ($this->itemMutationResolverFactory)($resourceClass, $rootResource, $resourceOperation) : ($this->itemSubscriptionResolverFactory)($resourceClass, $rootResource, $resourceOperation);
306+
$resolve = $rootOperation instanceof Mutation ? ($this->itemMutationResolverFactory)($resourceClass, $rootResource, $resolverOperation) : ($this->itemSubscriptionResolverFactory)($resourceClass, $rootResource, $resolverOperation);
302307
} elseif ($this->typeBuilder->isCollection($type)) {
303-
$resolve = ($this->collectionResolverFactory)($resourceClass, $rootResource, $resourceOperation);
308+
$resolve = ($this->collectionResolverFactory)($resourceClass, $rootResource, $resolverOperation);
304309
} else {
305-
$resolve = ($this->itemResolverFactory)($resourceClass, $rootResource, $resourceOperation);
310+
$resolve = ($this->itemResolverFactory)($resourceClass, $rootResource, $resolverOperation);
306311
}
307312

308313
return [
@@ -363,21 +368,21 @@ private function getGraphQlPaginationArgs(Operation $queryOperation): array
363368
return $args;
364369
}
365370

366-
private function getFilterArgs(array $args, ?string $resourceClass, string $rootResource, Operation $resourceOperation, Operation $rootOperation, ?string $property, int $depth): array
371+
private function getFilterArgs(array $args, ?string $resourceClass, string $rootResource, Operation $rootOperation, ?string $property, int $depth, ?AbstractOperation $operation = null): array
367372
{
368-
if (null === $resourceClass) {
373+
if (null === $operation || null === $resourceClass) {
369374
return $args;
370375
}
371376

372-
foreach ($resourceOperation->getFilters() ?? [] as $filterId) {
377+
foreach ($operation->getFilters() ?? [] as $filterId) {
373378
if (!$this->filterLocator->has($filterId)) {
374379
continue;
375380
}
376381

377382
foreach ($this->filterLocator->get($filterId)->getDescription($resourceClass) as $key => $value) {
378383
$nullable = isset($value['required']) ? !$value['required'] : true;
379384
$filterType = \in_array($value['type'], Type::$builtinTypes, true) ? new Type($value['type'], $nullable) : new Type('object', $nullable, $value['type']);
380-
$graphqlFilterType = $this->convertType($filterType, false, $resourceOperation, $rootOperation, $resourceClass, $rootResource, $property, $depth);
385+
$graphqlFilterType = $this->convertType($filterType, false, $rootOperation, $resourceClass, $rootResource, $property, $depth);
381386

382387
if (str_ends_with($key, '[]')) {
383388
$graphqlFilterType = GraphQLType::listOf($graphqlFilterType);
@@ -394,14 +399,14 @@ private function getFilterArgs(array $args, ?string $resourceClass, string $root
394399
array_walk_recursive($parsed, static function (&$value) use ($graphqlFilterType): void {
395400
$value = $graphqlFilterType;
396401
});
397-
$args = $this->mergeFilterArgs($args, $parsed, $resourceOperation, $key);
402+
$args = $this->mergeFilterArgs($args, $parsed, $operation, $key);
398403
}
399404
}
400405

401406
return $this->convertFilterArgsToTypes($args);
402407
}
403408

404-
private function mergeFilterArgs(array $args, array $parsed, ?Operation $operation = null, string $original = ''): array
409+
private function mergeFilterArgs(array $args, array $parsed, ?AbstractOperation $operation = null, string $original = ''): array
405410
{
406411
foreach ($parsed as $key => $value) {
407412
// Never override keys that cannot be merged
@@ -465,7 +470,7 @@ private function convertFilterArgsToTypes(array $args): array
465470
*
466471
* @throws InvalidTypeException
467472
*/
468-
private function convertType(Type $type, bool $input, Operation $resourceOperation, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth, bool $forceNullable = false): GraphQLType|ListOfType|NonNull
473+
private function convertType(Type $type, bool $input, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth, bool $forceNullable = false): GraphQLType|ListOfType|NonNull
469474
{
470475
$graphqlType = $this->typeConverter->convertType($type, $input, $rootOperation, $resourceClass, $rootResource, $property, $depth);
471476

@@ -482,7 +487,7 @@ private function convertType(Type $type, bool $input, Operation $resourceOperati
482487
}
483488

484489
if ($this->typeBuilder->isCollection($type)) {
485-
return $this->pagination->isGraphQlEnabled($resourceOperation) && !$input ? $this->typeBuilder->getResourcePaginatedCollectionType($graphqlType, $resourceOperation) : GraphQLType::listOf($graphqlType);
490+
return $this->pagination->isGraphQlEnabled($rootOperation) && !$input ? $this->typeBuilder->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $rootOperation) : GraphQLType::listOf($graphqlType);
486491
}
487492

488493
return $forceNullable || !$graphqlType instanceof NullableType || $type->isNullable() || ($rootOperation instanceof Mutation && 'update' === $rootOperation->getName())

src/GraphQl/Type/TypeBuilder.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public function getNodeInterface(): InterfaceType
210210
/**
211211
* {@inheritdoc}
212212
*/
213-
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, Operation $operation): GraphQLType
213+
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, string $resourceClass, Operation $operation): GraphQLType
214214
{
215215
$shortName = $resourceType->name;
216216
$paginationType = $this->pagination->getGraphQlPaginationType($operation);

src/GraphQl/Type/TypeBuilderInterface.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function getNodeInterface(): InterfaceType;
4343
/**
4444
* Gets the type of a paginated collection of the given resource type.
4545
*/
46-
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, Operation $operation): GraphQLType;
46+
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, string $resourceClass, Operation $operation): GraphQLType;
4747

4848
/**
4949
* Returns true if a type is a collection.

src/Metadata/Extractor/DynamicResourceExtractor.php

-50
This file was deleted.

src/Metadata/Extractor/DynamicResourceExtractorInterface.php

-24
This file was deleted.

src/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php

-4
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ public function create(string $resourceClass): ResourceMetadataCollection
6464
$resourceMetadataCollection = $this->decorated->create($resourceClass);
6565
}
6666

67-
if ($resourceMetadataCollection->isDynamic()) {
68-
return $resourceMetadataCollection;
69-
}
70-
7167
try {
7268
$reflectionClass = new \ReflectionClass($resourceClass);
7369
} catch (\ReflectionException) {

0 commit comments

Comments
 (0)