20
20
use ApiPlatform \Metadata \GraphQl \Mutation ;
21
21
use ApiPlatform \Metadata \GraphQl \Operation ;
22
22
use ApiPlatform \Metadata \GraphQl \Query ;
23
- use ApiPlatform \Metadata \GraphQl \QueryCollection ;
24
23
use ApiPlatform \Metadata \GraphQl \Subscription ;
25
- use ApiPlatform \Metadata \Operation as AbstractOperation ;
26
24
use ApiPlatform \Metadata \Property \Factory \PropertyMetadataFactoryInterface ;
27
25
use ApiPlatform \Metadata \Property \Factory \PropertyNameCollectionFactoryInterface ;
28
26
use ApiPlatform \Metadata \Resource \Factory \ResourceMetadataCollectionFactoryInterface ;
47
45
*/
48
46
final class FieldsBuilder implements FieldsBuilderInterface
49
47
{
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 )
48
+ 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 , private readonly ?ResourceMetadataCollectionFactoryInterface $ graphQlNestedOperationResourceMetadataFactory = null )
51
49
{
52
50
}
53
51
@@ -256,7 +254,23 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
256
254
$ resourceClass = $ type ->getClassName ();
257
255
}
258
256
259
- $ graphqlType = $ this ->convertType ($ type , $ input , $ rootOperation , $ resourceClass ?? '' , $ rootResource , $ property , $ depth , $ forceNullable );
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 we force one to exist
264
+ $ nestedResourceMetadataCollection = $ this ->graphQlNestedOperationResourceMetadataFactory ->create ($ resourceClass );
265
+ $ resourceOperation = $ nestedResourceMetadataCollection ->getOperation ($ isCollectionType ? 'collection_query ' : 'item_query ' );
266
+ }
267
+ }
268
+
269
+ if (!$ resourceOperation instanceof Operation) {
270
+ throw new \LogicException ('The resource operation should be a GraphQL operation. ' );
271
+ }
272
+
273
+ $ graphqlType = $ this ->convertType ($ type , $ input , $ resourceOperation , $ rootOperation , $ resourceClass ?? '' , $ rootResource , $ property , $ depth , $ forceNullable );
260
274
261
275
$ graphqlWrappedType = $ graphqlType instanceof WrappingType ? $ graphqlType ->getWrappedType (true ) : $ graphqlType ;
262
276
$ isStandardGraphqlType = \in_array ($ graphqlWrappedType , GraphQLType::getStandardTypes (), true );
@@ -271,43 +285,22 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
271
285
272
286
$ args = [];
273
287
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
-
285
288
if (!$ input && !$ rootOperation instanceof Mutation && !$ rootOperation instanceof Subscription && !$ isStandardGraphqlType && $ isCollectionType ) {
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
- }
289
+ if ($ this ->pagination ->isGraphQlEnabled ($ resourceOperation )) {
290
+ $ args = $ this ->getGraphQlPaginationArgs ($ resourceOperation );
298
291
}
299
292
300
- $ args = $ this ->getFilterArgs ($ args , $ resourceClass , $ rootResource , $ rootOperation , $ property , $ depth , $ operation );
293
+ $ args = $ this ->getFilterArgs ($ args , $ resourceClass , $ rootResource , $ resourceOperation , $ rootOperation , $ property , $ depth );
301
294
}
302
295
303
296
if ($ isStandardGraphqlType || $ input ) {
304
297
$ resolve = null ;
305
298
} elseif (($ rootOperation instanceof Mutation || $ rootOperation instanceof Subscription) && $ depth <= 0 ) {
306
- $ resolve = $ rootOperation instanceof Mutation ? ($ this ->itemMutationResolverFactory )($ resourceClass , $ rootResource , $ resolverOperation ) : ($ this ->itemSubscriptionResolverFactory )($ resourceClass , $ rootResource , $ resolverOperation );
299
+ $ resolve = $ rootOperation instanceof Mutation ? ($ this ->itemMutationResolverFactory )($ resourceClass , $ rootResource , $ resourceOperation ) : ($ this ->itemSubscriptionResolverFactory )($ resourceClass , $ rootResource , $ resourceOperation );
307
300
} elseif ($ this ->typeBuilder ->isCollection ($ type )) {
308
- $ resolve = ($ this ->collectionResolverFactory )($ resourceClass , $ rootResource , $ resolverOperation );
301
+ $ resolve = ($ this ->collectionResolverFactory )($ resourceClass , $ rootResource , $ resourceOperation );
309
302
} else {
310
- $ resolve = ($ this ->itemResolverFactory )($ resourceClass , $ rootResource , $ resolverOperation );
303
+ $ resolve = ($ this ->itemResolverFactory )($ resourceClass , $ rootResource , $ resourceOperation );
311
304
}
312
305
313
306
return [
@@ -368,21 +361,21 @@ private function getGraphQlPaginationArgs(Operation $queryOperation): array
368
361
return $ args ;
369
362
}
370
363
371
- private function getFilterArgs (array $ args , ?string $ resourceClass , string $ rootResource , Operation $ rootOperation , ?string $ property , int $ depth, ? AbstractOperation $ operation = null ): array
364
+ private function getFilterArgs (array $ args , ?string $ resourceClass , string $ rootResource , Operation $ resourceOperation , Operation $ rootOperation , ?string $ property , int $ depth ): array
372
365
{
373
- if (null === $ operation || null === $ resourceClass ) {
366
+ if (null === $ resourceClass ) {
374
367
return $ args ;
375
368
}
376
369
377
- foreach ($ operation ->getFilters () ?? [] as $ filterId ) {
370
+ foreach ($ resourceOperation ->getFilters () ?? [] as $ filterId ) {
378
371
if (!$ this ->filterLocator ->has ($ filterId )) {
379
372
continue ;
380
373
}
381
374
382
375
foreach ($ this ->filterLocator ->get ($ filterId )->getDescription ($ resourceClass ) as $ key => $ value ) {
383
376
$ nullable = isset ($ value ['required ' ]) ? !$ value ['required ' ] : true ;
384
377
$ filterType = \in_array ($ value ['type ' ], Type::$ builtinTypes , true ) ? new Type ($ value ['type ' ], $ nullable ) : new Type ('object ' , $ nullable , $ value ['type ' ]);
385
- $ graphqlFilterType = $ this ->convertType ($ filterType , false , $ rootOperation , $ resourceClass , $ rootResource , $ property , $ depth );
378
+ $ graphqlFilterType = $ this ->convertType ($ filterType , false , $ resourceOperation , $ rootOperation , $ resourceClass , $ rootResource , $ property , $ depth );
386
379
387
380
if (str_ends_with ($ key , '[] ' )) {
388
381
$ graphqlFilterType = GraphQLType::listOf ($ graphqlFilterType );
@@ -399,14 +392,14 @@ private function getFilterArgs(array $args, ?string $resourceClass, string $root
399
392
array_walk_recursive ($ parsed , static function (&$ value ) use ($ graphqlFilterType ): void {
400
393
$ value = $ graphqlFilterType ;
401
394
});
402
- $ args = $ this ->mergeFilterArgs ($ args , $ parsed , $ operation , $ key );
395
+ $ args = $ this ->mergeFilterArgs ($ args , $ parsed , $ resourceOperation , $ key );
403
396
}
404
397
}
405
398
406
399
return $ this ->convertFilterArgsToTypes ($ args );
407
400
}
408
401
409
- private function mergeFilterArgs (array $ args , array $ parsed , ?AbstractOperation $ operation = null , string $ original = '' ): array
402
+ private function mergeFilterArgs (array $ args , array $ parsed , ?Operation $ operation = null , string $ original = '' ): array
410
403
{
411
404
foreach ($ parsed as $ key => $ value ) {
412
405
// Never override keys that cannot be merged
@@ -470,7 +463,7 @@ private function convertFilterArgsToTypes(array $args): array
470
463
*
471
464
* @throws InvalidTypeException
472
465
*/
473
- private function convertType (Type $ type , bool $ input , Operation $ rootOperation , string $ resourceClass , string $ rootResource , ?string $ property , int $ depth , bool $ forceNullable = false ): GraphQLType |ListOfType |NonNull
466
+ 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
474
467
{
475
468
$ graphqlType = $ this ->typeConverter ->convertType ($ type , $ input , $ rootOperation , $ resourceClass , $ rootResource , $ property , $ depth );
476
469
@@ -487,7 +480,7 @@ private function convertType(Type $type, bool $input, Operation $rootOperation,
487
480
}
488
481
489
482
if ($ this ->typeBuilder ->isCollection ($ type )) {
490
- return $ this ->pagination ->isGraphQlEnabled ($ rootOperation ) && !$ input ? $ this ->typeBuilder ->getResourcePaginatedCollectionType ($ graphqlType , $ resourceClass , $ rootOperation ) : GraphQLType::listOf ($ graphqlType );
483
+ return $ this ->pagination ->isGraphQlEnabled ($ resourceOperation ) && !$ input ? $ this ->typeBuilder ->getResourcePaginatedCollectionType ($ graphqlType , $ resourceClass , $ resourceOperation ) : GraphQLType::listOf ($ graphqlType );
491
484
}
492
485
493
486
return $ forceNullable || !$ graphqlType instanceof NullableType || $ type ->isNullable () || ($ rootOperation instanceof Mutation && 'update ' === $ rootOperation ->getName ())
0 commit comments