@@ -290,9 +290,111 @@ public function resolveResourceArgs(array $args, Operation $operation): array
290
290
$ args [$ id ]['type ' ] = $ this ->typeConverter ->resolveType ($ arg ['type ' ]);
291
291
}
292
292
293
+ /*
294
+ * This is @experimental, read the comment on the parameterToObjectType function as additional information.
295
+ */
296
+ foreach ($ operation ->getParameters () ?? [] as $ parameter ) {
297
+ $ key = $ parameter ->getKey ();
298
+
299
+ if (str_contains ($ key , ':property ' )) {
300
+ if (!($ filterId = $ parameter ->getFilter ()) || !$ this ->filterLocator ->has ($ filterId )) {
301
+ continue ;
302
+ }
303
+
304
+ $ parsedKey = explode ('[:property] ' , $ key );
305
+ $ flattenFields = [];
306
+ foreach ($ this ->filterLocator ->get ($ filterId )->getDescription ($ operation ->getClass ()) as $ key => $ value ) {
307
+ $ values = [];
308
+ parse_str ($ key , $ 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
+ continue ;
319
+ }
320
+
321
+ $ args [$ key ] = ['type ' => GraphQLType::string ()];
322
+
323
+ if ($ parameter ->getRequired ()) {
324
+ $ args [$ key ]['type ' ] = GraphQLType::nonNull ($ args [$ key ]['type ' ]);
325
+ }
326
+ }
327
+
293
328
return $ args ;
294
329
}
295
330
331
+ /**
332
+ * Transform the result of a parse_str to a GraphQL object type.
333
+ * We should consider merging getFilterArgs and this, `getFilterArgs` uses `convertType` whereas we assume that parameters have only scalar types.
334
+ * Note that this method has a lower complexity then the `getFilterArgs` one.
335
+ * TODO: Is there a use case with an argument being a complex type (eg: a Resource, Enum etc.)?
336
+ *
337
+ * @param array<array{name: string, required: bool|null, description: string|null, leafs: string|array, type: string}> $flattenFields
338
+ */
339
+ private function parameterToObjectType (array $ flattenFields , string $ name ): InputObjectType
340
+ {
341
+ $ fields = [];
342
+ foreach ($ flattenFields as $ field ) {
343
+ $ key = $ field ['name ' ];
344
+ $ type = $ this ->getParameterType (\in_array ($ field ['type ' ], Type::$ builtinTypes , true ) ? new Type ($ field ['type ' ], !$ field ['required ' ]) : new Type ('object ' , !$ field ['required ' ], $ field ['type ' ]));
345
+
346
+ if (\is_array ($ l = $ field ['leafs ' ])) {
347
+ if (0 === key ($ l )) {
348
+ $ key = $ key ;
349
+ $ type = GraphQLType::listOf ($ type );
350
+ } else {
351
+ $ n = [];
352
+ foreach ($ field ['leafs ' ] as $ l => $ value ) {
353
+ $ n [] = ['required ' => null , 'name ' => $ l , 'leafs ' => $ value , 'type ' => 'string ' , 'description ' => null ];
354
+ }
355
+
356
+ $ type = $ this ->parameterToObjectType ($ n , $ key );
357
+ if (isset ($ fields [$ key ]) && ($ t = $ fields [$ key ]['type ' ]) instanceof InputObjectType) {
358
+ $ t = $ fields [$ key ]['type ' ];
359
+ $ t ->config ['fields ' ] = array_merge ($ t ->config ['fields ' ], $ type ->config ['fields ' ]);
360
+ $ type = $ t ;
361
+ }
362
+ }
363
+ }
364
+
365
+ if ($ field ['required ' ]) {
366
+ $ type = GraphQLType::nonNull ($ type );
367
+ }
368
+
369
+ if (isset ($ fields [$ key ])) {
370
+ if ($ type instanceof ListOfType) {
371
+ $ key .= '_list ' ;
372
+ }
373
+ }
374
+
375
+ $ fields [$ key ] = ['type ' => $ type , 'name ' => $ key ];
376
+ }
377
+
378
+ return new InputObjectType (['name ' => $ name , 'fields ' => $ fields ]);
379
+ }
380
+
381
+ /**
382
+ * A simplified version of convert type that does not support resources.
383
+ */
384
+ private function getParameterType (Type $ type ): GraphQLType
385
+ {
386
+ return match ($ type ->getBuiltinType ()) {
387
+ Type::BUILTIN_TYPE_BOOL => GraphQLType::boolean (),
388
+ Type::BUILTIN_TYPE_INT => GraphQLType::int (),
389
+ Type::BUILTIN_TYPE_FLOAT => GraphQLType::float (),
390
+ Type::BUILTIN_TYPE_STRING => GraphQLType::string (),
391
+ Type::BUILTIN_TYPE_ARRAY => GraphQLType::listOf ($ this ->getParameterType ($ type ->getCollectionValueTypes ()[0 ])),
392
+ Type::BUILTIN_TYPE_ITERABLE => GraphQLType::listOf ($ this ->getParameterType ($ type ->getCollectionValueTypes ()[0 ])),
393
+ Type::BUILTIN_TYPE_OBJECT => GraphQLType::string (),
394
+ default => GraphQLType::string (),
395
+ };
396
+ }
397
+
296
398
/**
297
399
* Get the field configuration of a resource.
298
400
*
@@ -450,9 +552,9 @@ private function getFilterArgs(array $args, ?string $resourceClass, string $root
450
552
}
451
553
}
452
554
453
- foreach ($ this ->filterLocator ->get ($ filterId )->getDescription ($ entityClass ) as $ key => $ value ) {
454
- $ nullable = isset ($ value ['required ' ]) ? !$ value ['required ' ] : true ;
455
- $ filterType = \in_array ($ value ['type ' ], Type::$ builtinTypes , true ) ? new Type ($ value ['type ' ], $ nullable ) : new Type ('object ' , $ nullable , $ value ['type ' ]);
555
+ foreach ($ this ->filterLocator ->get ($ filterId )->getDescription ($ entityClass ) as $ key => $ description ) {
556
+ $ nullable = isset ($ description ['required ' ]) ? !$ description ['required ' ] : true ;
557
+ $ filterType = \in_array ($ description ['type ' ], Type::$ builtinTypes , true ) ? new Type ($ description ['type ' ], $ nullable ) : new Type ('object ' , $ nullable , $ description ['type ' ]);
456
558
$ graphqlFilterType = $ this ->convertType ($ filterType , false , $ resourceOperation , $ rootOperation , $ resourceClass , $ rootResource , $ property , $ depth );
457
559
458
560
if (str_ends_with ($ key , '[] ' )) {
@@ -467,8 +569,8 @@ private function getFilterArgs(array $args, ?string $resourceClass, string $root
467
569
if (\array_key_exists ($ key , $ parsed ) && \is_array ($ parsed [$ key ])) {
468
570
$ parsed = [$ key => '' ];
469
571
}
470
- array_walk_recursive ($ parsed , static function (&$ value ) use ($ graphqlFilterType ): void {
471
- $ value = $ graphqlFilterType ;
572
+ array_walk_recursive ($ parsed , static function (&$ v ) use ($ graphqlFilterType ): void {
573
+ $ v = $ graphqlFilterType ;
472
574
});
473
575
$ args = $ this ->mergeFilterArgs ($ args , $ parsed , $ resourceOperation , $ key );
474
576
}
0 commit comments